【问题标题】:preg_match a php string with simple or double quotes escaped insidepreg_match 一个带有简单或双引号的 php 字符串,其中转义了
【发布时间】:2014-02-27 13:33:54
【问题描述】:

我想解析一些包含类似这样的 php 文件:

// form 1
__('some string');
// form 2
__('an other string I\'ve written with a quote');
// form 3
__('an other one
multiline');
// form 4
__("And I want to handle double quotes too !");
// form 5
__("And I want to handle double quotes too !", $second_parameter_may_happens);

以下正则表达式匹配除第二个之外的所有内容

preg_match_all('#__\((\'|")(.*)\1(?:,.*){0,1}\)#smU', $file_content);

【问题讨论】:

  • 不要使用正则表达式,至少不要使用应该一次完成所有操作的正则表达式。即使你让它在实践中工作,证明它总是有效的困难和需要进行更改时的可维护性噩梦也不值得。

标签: php regex


【解决方案1】:

你可以使用这个模式:

$pattern = '~__\((["\'])(?<param1>(?>[^"\'\\\]+|\\\.|(?!\1)["\'])*)\1(?:,\s*(?<param2>\$[a-z0-9_-]+))?\);~si';

if (preg_match_all($pattern, $data, $matches, PREG_SET_ORDER))
    print_r($matches);

但正如 Jon 所注意到的,这种模式可能难以维护。这就是为什么,我建议将模式更改为:

$pattern = <<<'LOD'
~
## definitions
(?(DEFINE)
    (?<sqc>        # content between single quotes
        (?> [^'\\]+  | \\. )* #'
        # can be written in a more efficient way, with an unrolled pattern:
        # [^'\\]*+ (?:\\. ['\\]*)*+
    )
    (?<dqc>        # content between double quotes
        (?> [^"\\]+  | \\. )* #"
    )
    (?<var>        # variable
        \$ [a-zA-Z0-9_-]+
    )
)

## main pattern
__\(
(?| " (?<param1> \g<dqc> ) " | ' (?<param1> \g<sqc> ) ' )
# note that once you define a named group in the first branch in a branch reset
# group, you don't have to include the name in other branches:
# (?| " (?<param1> \g<dgc>) " | ' ( \g<sqc> ) ' ) does the same. Even if the 
# second branch succeeds, the capture group will be named as in the first branch.
# Only the order of groups is taken in account.
(?:, \s* (?<param2> \g<var> ) )?
\);
~xs
LOD;

这个简单的更改使您的模式更具可读性和可编辑性。

引号之间的内容 子模式旨在处理转义的引号。这个想法是匹配所有前面有反斜杠的字符(可以是反斜杠本身),以确保匹配文字反斜杠和转义引号::

\'           # an escaped quote 
\\'        #'# an escaped backslash and a quote
\\\'         # an escaped backslash and an escaped quote
\\\\'      #'# two escaped backslashes and a quote
...

子模式详情:

(?>            # open an atomic group (inside which the bactracking is forbiden)
    [^'\\]+  #'# all that is not a quote or a backslash
  |            # OR
    \\.        # an escaped character
)*             # repeat the group zero or more times

【讨论】:

  • 感谢您的完整回复,但您的“扩展版”不起作用:/
  • @Asenar:我已经测试了这两个版本,它们运行良好。我建议你在 PHP 脚本的开头写:ini_set('display_errors', 'On'); 来查找错误。
  • 过失!它正在工作,但我仍然使用 $match[2] 而不是 $match['param1'];谢谢!
  • @Asenar:是的,请注意,当您在 DEFINE 区域中创建命名子模式时,主区域中每个组的数量会发生变化。
【解决方案2】:

我终于根据我的第一个表达找到了解决方案,所以我会写它,但是使用Casimir的扩展风格,他的回答非常好

$pattern = <<<'LOD'
#
  __\(
    (?<quote>'|")  # catch the opening quote
    (?<param1>
      (?:
        [^'"]        # anything but quoteS
      |
        \\'          # escaped single quote are ok
      |
        \\"          # escaped double quote are ok too
      )*
    )
    \k{quote}             # find the closing quote
    (?:,.*){0,1}          # catch any type of 2nd parameter
  \)
#smUx               # x to allow comments :)
LOD;

【讨论】:

    猜你喜欢
    • 2015-10-27
    • 1970-01-01
    • 1970-01-01
    • 2015-12-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-29
    • 1970-01-01
    相关资源
    最近更新 更多