skip to Main Content

I have created a regular expression to add ?. to JavaScript expressions within a string.

For example: bar.foo.some becomes bar?.foo?.some.

It works perfectly, except when there are dots between quotes (' or ").
I mean, when I test the regex on this expression: data.foo ? 'yes. I can do it': 'no.', it becomes data?.foo ? 'yes?. I can do it': 'no?.'.

What I need from this regex is to ignore the dots inside the quotes. However, I am unsure how to instruct the regex to do so.

The regex I created is quite complex as it covers cases such as ?.[ and )?. for index access, as well as function calls (some[...] and some.fn().bar).

Below are some possible expressions with the expected output as comments:

[
  `bla.params.query ? 'yes.' : 'no.'`, // expected output: bla?.params?.query ? 'yes.': 'no.'
  `bla[foo]`, // expected output: bla?.[foo]
  `bla[foo].bar }}`, // expected output: bla?.[foo]?.bar
  `bar.some().bar`, // expected output: bla?.some()?.bar
  `bla`, // expected output: bla
  `bla.some`, // expected output: bla?.some
  `bla.some.go`, // expected output: bla?.some?.go
  `bla ? 'bla.some': 'you.go'`, // expected output: bla ? 'bla.some': 'you.go'
  `bla.`, // invalid expresssion, should ignore because there nothing after the dot. expected output: bla.
].forEach((v) => {
  v = v.replace(
    /(?<=[a-z_]).(?!?)|(?<=[]a-z_])(?=[)|(?<=[]a-z_])(?=^()|(?<=]|))(?=[)|(?<=]|))./gi,
    '?.'
  );

  console.log(v);
});

2

Answers


  1. To skip . inside single or double quotes, you can use a negative lookahead to ensure that the . is not followed by a closing quote. Here’s the updated regex:

    /(?<=[a-z_]).(?!?)(?=(?:[^'"]|'[^']*'|"[^"]*")*$)|(?<=[]a-z_])(?=[)|(?<=[]a-z_])(?=^()|(?<=]|))(?=[)|(?<=]|))./gi
    

    This regex is similar to the previous one, but it adds a lookahead assertion to check that the . is not followed by a closing quote. The lookahead matches any number of characters that are not a quote or a quote that is not followed by another quote. This ensures that the . is not inside a quoted string.

    [
      `bla.params.query ? 'yes.' : 'no.'`, // expected output: bla?.params?.query ? 'yes.': 'no.'
      `bla[foo]`, // expected output: bla?.[foo]
      `bla[foo].bar }}`, // expected output: bla?.[foo]?.bar
      `bar.some().bar`, // expected output: bla?.some()?.bar
      `bla`, // expected output: bla
      `bla.some`, // expected output: bla?.some
      `bla.some.go`, // expected output: bla?.some?.go
      `bla ? 'bla.some': 'you.go'`, // expected output: bla ? 'bla.some': 'you.go'
      `bla.`, // invalid expresssion, should ignore because there nothing after the dot. expected output: bla.
    ].forEach((v) => {
      v = v.replace(
        /(?<=[a-z_]).(?!?)(?=(?:[^'"]|'[^']*'|"[^"]*")*$)|(?<=[]a-z_])(?=[)|(?<=[]a-z_])(?=^()|(?<=]|))(?=[)|(?<=]|))./gi,
        '?.'
      );
    
      console.log(v);
    });
    Login or Signup to reply.
  2. It seems that is that it fails to distinguish between dots inside strings and dots used as property access operators in JavaScript objects.

    RegExp is designed for linear pattern matching, in your case it needs to ingore something with double quotes or single quotes and it is not RegExp’s forte.

    a solution cuold be to break the sting into piece and apply regex to non string parts like this:

     function safeRegexReplace(str, regex, replacement) {
        var parts = str.split(/(".*?"|'.*?')/); // or .(?!?|$)
    
        // for loop for the parts without quotes
        for (var i = 0; i < parts.length; i++) {
            if (i % 2 === 0) { // If the index is even, we are not inside a string
                parts[i] = parts[i].replace(regex, replacement);
            }
        }
    
        // Join all
        return parts.join('');
    }
    
    [
      expected outputs
    ].forEach((v) => {
      v = safeRegexReplace(v, /(?<=[a-z_]).(?!?)|(?<=[]a-z_])(?=[)|(?<=[]a-z_])(?=^()|(?<=]|))(?=[)|(?<=]|))./gi, '?.'); //every little combination
      console.log(v);
    });
    

    i’m assuming that the string does not cointain nested strings

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search