1

I try to find lines with a number of strings in any order.
Next I replace the strings within the lines with <mark>string-n</mark>.

I use a small parser which translates "string-1&&string-2&&string-N' into
a regex pattern: (?=.*(string-1))(?=.*(string-2))(?=.*(string-N)).*

This works fine to find lines with at least all N strings, but there must be a much better way to replace / mark the strings per line.

The code:

function replacer() {
    console.log('args', arguments);
    const arg_len = arguments.length;
    let result =  arguments[arg_len - 1];
    for (let i = 1; i < arg_len - 2; i++) {
        let re = new RegExp(arguments[i], 'gum');
        result = result.replace(re, `<mark>${arguments[i]}</mark>`);
    }
    return result
}
function testAndPattern(one_test_line) {
    const and_pattern = 'string-1&&string-2&&string-n';
    const regex_pattern = buildRexPattern(and_pattern);
    let result = one_test_line.replace(new RegExp(regex_pattern,"gum"), replacer);
    console.log('result', result);

The replacer arguments object shows one time: {0: '..one_test_line..', 1:'string-1', 2:'string-2', 3:'string-n', 4:0, 5: '..One_test_line..'} The result is also fine. But I needed to use a lot of regular expressions in the replacer.

There must be another and easy way in javascript. Substring replacing is not really happening here.

"one_test_line" is actually a HTML table col with transaction descriptions. But it good be this example:
"The quick brown fox jumps over the lazy dog" and replacing 'dog', 'own' and 'jumps over', giving:

"The quick br<mark>own</mark> fox <mark>jumps over</mark> the lazy <mark>dog</mark>"  

Without the dog, nothing will be replaced / marked in this example.

Update: while looking at the problem again I came up with a regex OR in the replacer like /string-1|string-2|string-N/g because in the replacer we know all N strings are present.

    function marker(arg) {
        return `<mark>${arg}</mark>`;
    }
    function replacer(re_or) {
        return function() {
            return arguments[0].replace(re_or, marker)
        }
    }
    function testAndPattern(one_test_line) {
        const and_pattern = 'string-1&&string-2&&string-n'
        const or_pattern = and_pattern.split('&&').join('|');
        const regex_pattern = buildRexPattern(and_pattern);
        let result = one_test_line.replace(new RegExp(regex_pattern,"gum"), replacer(new RegExp(`(${or_pattern})`,"gum")));
        console.log('result', result);
    }
voscausa
  • 11,253
  • 2
  • 39
  • 67
  • What's the intended input/output here? What are you replacing in batches? Also, is [this question](http://stackoverflow.com/questions/15604140/replace-multiple-strings-with-multiple-other-strings) relevant here? – VLAZ Oct 27 '16 at 15:54
  • An OR regex in the replacer seems to be the best solution. But notice you shouldn't build it from the capturing groups that are passed to your replacer, but rather build it from the `and_pattern` like you do in `buildRegexPattern`. – Bergi Oct 27 '16 at 18:11
  • I have updated my question with the code, which works fine and YES I pass the re_or to the replacer. – voscausa Oct 27 '16 at 18:33
  • 1
    @voscausa Nice, that's what I would've done as well (maybe with a named parameter instead of `arguments[0]`, but still). You should [post it as an answer](http://stackoverflow.com/help/self-answer) instead of editing your question. – Bergi Oct 27 '16 at 23:26

1 Answers1

1

While looking at the problem again, I came up with a regex OR in the replacer like /string-1|string-2|string-N/g because in the replacer we know all N strings are present.

function marker(arg) {
    return `<mark>${arg}</mark>`;
}
function replacer(re_or) {
    return function(match) {
        return match.replace(re_or, marker)
    }
}
function testAndPattern(one_test_line) {
    const and_pattern = 'string-1&&string-2&&string-n'
    const or_pattern = and_pattern.split('&&').join('|');
    const regex_pattern = buildRexPattern(and_pattern);
    let result = one_test_line.replace(new RegExp(regex_pattern,"gum"), replacer(new RegExp(`(${or_pattern})`,"gum")));
    console.log('result', result);
}

Below the parser:

function buildRexPattern(raw_pattern) {
    let pattern = '';
    const p_list = raw_pattern.split('&&');
    // search and-ed list items in any order 
    if (p_list.length > 1) {
        for (let i = 0; i < p_list.length; i++) {
            pattern += `(?=.*(${p_list[i]}))`
        }
        pattern += '.*';
        return  pattern;
    } else {
        // search or-ed items in any order, example 'string-1|string-2|string-N'
        return raw_pattern;
    }
}
voscausa
  • 11,253
  • 2
  • 39
  • 67