0

I want to find all occurences of % that are not within quotation characters.

Example> "test% testing % '% hello' " would return ["%","%"]

Looking at another stack overflow thread this is what I found:

var patt = /!["'],*%,*!['"]/g

var str = "testing 123 '%' % '% ' "
var res = str.match(patt);

However this gives me null. Have you any tips of what I should do?

Demo

user1506145
  • 5,176
  • 11
  • 46
  • 75

4 Answers4

2

You could try the below positive lookahead assertion based regex.

> var s = "test% testing % '% hello' "
> s.match(/%(?=(?:[^']*'[^']*')*[^']*$)/g)
[ '%', '%' ]
> var str = "testing %"
undefined
> str.match(/%(?=(?:[^']*'[^']*')*[^']*$)/g)
[ '%' ]
> var str1 = "testing '%'"
undefined
> str1.match(/%(?=(?:[^']*'[^']*')*[^']*$)/g)
null
Avinash Raj
  • 172,303
  • 28
  • 230
  • 274
1

Try this:

var patt=  /[^"'].*?(%).*?[^'"]/g ;
var str = "testing 123 '%' % '% ' "
var res = str.match(patt);
console.dir(res[1]); // result will be in the 1st match group: res[1]

Here is the link to the online testing.

Explanation:

  • [^"'] - any character except " or '
  • .*? any characters (except new line) any times or zero times not greedy.

Update

Actually you must check if behing and ahead of % there are no quotes. But:

JavaScript regular expressions do not support lookbehinds

So you have no way to identify " or ' preceding % sign unless more restrictions are applied.

I'd suggest to do searching in php or other language (where lookbehind is supported) or impose more conditions.

Community
  • 1
  • 1
Igor Savinkin
  • 5,669
  • 8
  • 37
  • 69
1

Since I'm not a big fan of regular expressions, here's my approach.
What is important in my answer, if there would be a trailing quote in the string, the other answers won't work. In other words, only my answer works in cases where there is odd number of quotes.

function countUnquoted(str, charToCount) {
    var i = 0,
        len = str.length,
        count = 0,
        suspects = 0,
        char,
        flag = false;

    for (; i < len; i++) {
        char = str.substr(i, 1);

        if ("'" === char) {
            flag = !flag;
            suspects = 0;
        } else if (charToCount === char && !flag) {
            count++;
        } else if (charToCount === char) {
            suspects++;
        }
    }

    //this way we can also count occurences in such situation
    //that the quotation mark has been opened but not closed till the end of string
    if (flag) {
        count += suspects;
    }

    return count;
}

As far as I believe, you wanted to count those percent signs, so there's no need to put them in an array.

In case you really, really need to fill this array, you can do it like that:

function matchUnquoted(str, charToMatch) {
  var res = [],
      i = 0,
      count = countUnquoted(str, charToMatch);

  for (; i < count; i++) {
    res.push('%');
  }

  return res;
}

matchUnquoted("test% testing % '% hello' ", "%");

Trailing quote

Here's a comparison of a case when there is a trailing ' (not closed) in the string.

> var s = "test% testing % '% hello' asd ' asd %"
> matchUnquoted(s, '%')
['%', '%', '%']
>
> // Avinash Raj's answer
> s.match(/%(?=(?:[^']*'[^']*')*[^']*$)/g)
['%', '%']
matewka
  • 9,912
  • 2
  • 32
  • 43
0

Use this regex: (['"]).*?\1|(%) and the second capture group will have all the % signs that are not inside single or double quotes.

Breakdown:

(['"]).*?\1 captures a single or double quote, followed by anything (lazy) up to a matching single or double quote

|(%) captures a % only if it wasn't slurped up by the first part of the alternation (i.e., if it's not in quotes)

Brian Stephens
  • 5,161
  • 19
  • 25