سؤال

I'm using the following expression to find the number of occurences of ' and " in a string I don't want the count to include \' or \".

$subStr = 'asdf"asdf""a\\"sdf\'asdf\'\'a\\\'sdf';
preg_match_all('/[^\\\\]\'|[^\\\\]\"/', $subStr, $matches);
echo count($matches[0]);

I expect it to return 6 but it only returns 4. I think this is because the strings "" and '' are only count once.

This is what $matches contain:

Array
(
    [0] => Array
        (
            [0] => f"
            [1] => f"
            [2] => f'
            [3] => f'
        )

)

Is there any way I can get the count of 6? Note that I also need to exclude the \" and \'.

هل كانت مفيدة؟

المحلول

Why doesn't it work

You can't use a character class to match a character not preceded by another character. This is because a character class (negated or not) must still match a character. For example, [^a]b does not mean "b not preceded by a". It means: "a character that's not a followed by b".

The Solution

If you want to match a single-quote or double-quote character not preceded by a backslash, then you'll have to use a lookaround expression (a negative lookbehind, specifically).

The regex you're looking for is (?<!\\\\)[\'"].

Autopsy:

  • (?<! - start of the lookbehind expression
    • \\\\ - match a literal backslash character
  • ) - end of the lookbehind expression
  • [\'"] - character class that matches a single character from the list "'

Visual Representation:

Visual Representation of the regex

This effectively matches any single-quote / double-quote character that is not preceded by a literal backslash character.

Using the above expression with preg_match_all is simple:

$subStr = 'asdf"asdf""a\\"sdf\'asdf\'\'a\\\'sdf';
preg_match_all('/(?<!\\\\)[\'"]/', $subStr, $matches);
echo count($matches[0]); // => 6

Demo

نصائح أخرى

preg_match_all('/([\'"])/', $subStr, $matches);

Alternately:

print count(preg_split('/[\'"]/', $subStr)) - 1;

Update: if you want to escape \' or \"

preg_match_all('/(?<!\\\)([\'"])/', $subStr, $matches);

You could, of course, go for a non-regex approach too:

$number = substr_count($string, '"') + substr_count($string, "'");

Try this...

$subStr = 'asdf"asdf""asdf\'asdf\'\'asdf';
preg_match_all('/["\']/', $subStr, $matches);
echo count($matches[0]);

Demo

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top