问题正则表达模式寻找类似匹配

I have one of the four patter:

"Test"
'Test'
`Test`
(Test)

Is it possible to get "Test" with a single preg_match call?

I tried the following:

if ( preg_match( '/^(?:"(.*)"|\'(.*)\'|`(.*)`|\((.*)\')$/iu', $pattern, $matches ) )

... but this gives me five elements of $matches back. But I would like to have two only (One for the whole match and one for the found match with "Test" in it.)

You can use dot to match the characters aroun d the word and use array_unique to remove duplicates.

preg_match_all("/.(\w+)./", $str,$match);
foreach($match as &$m) $m = array_unique($m);

var_dump($match);

https://3v4l.org/T2hnh

array(2) {
  [0]=>
  array(4) {
    [0]=>
    string(6) ""Test""
    [1]=>
    string(6) "'Test'"
    [2]=>
    string(6) "`Test`"
    [3]=>
    string(6) "(Test)"
  }
  [1]=>
  &array(1) {
    [0]=>
    string(4) "Test"
  }
}

You can use non-capturing groups :

 '/^(?:"|\'|`|\()(.*)(?:"|\'|`|\))$/iu'

So just the (.*) group will capture data.

Your regex could be:

^['"`(](.+)['"`)]$

Which would give off the following code in PHP:

if(preg_match('^[\'"`(](.+)[\'"`)]$', $pattern, $matches))

Explanation

In Regex, character groups—marked with enclosing square brackets []— matches one of the characters inside of it.

To make sure that the single quote, back tick and double quote and have the same closing char you might use a capturing group with a backreference to that group.

To get the same group in the alternation to also match ( with the closing ) you might use a branch reset group.

The match for Test is in group 2

(?|(["'`])(Test)\1|\(((Test)\)))

Explanation

  • (?| Branch reset group
    • (["'`]) Capture in group 1 any of the listed
    • (Test)\1 Capture in group 2 matching Test followed by a backreference \1 to group 1
    • | Or
    • \(((Test)\)) Match (, capture in group 2 matching Test followed by )
  • ) Close branch reset group

Regex demo | Php demo

For example:

$strings = [
    "\"Test\"",
    "'Test'",
    "`Test`",
    "(Test)",
    "Test\"",
    "'Test",
    "Test`",
    "(Test",
    "\"Test'",
    "'Test\"",
    "`Test",
    "Test)",
];
$pattern = '/(?|(["\'`])(Test)\1|\(((Test)\)))/';
foreach ($strings as $string){
    $isMatch = preg_match($pattern, $string, $matches);
    if ($isMatch) {
        echo "Match $string ==> " . $matches[2] . PHP_EOL;
    }
}

Result

Match "Test" ==> Test
Match 'Test' ==> Test
Match `Test` ==> Test
Match (Test) ==> Test