【问题标题】:How to grab code inside curly braces correctly?如何正确抓取花括号内的代码?
【发布时间】:2012-03-30 11:36:22
【问题描述】:

我需要某种正则表达式来获取花括号内的部分代码。关于这个还有其他问题,但我的有点不同。

将此代码视为示例;

public function my_method($my_input) {
    if(true == false) { $me = "Forever alone. :("; }
    if(true == true) { $me = "No longer alone. :}"; }
    if(false == false) { $me = ":{ - This is so Wrong."; }
}

并忽略“public function my_method($my_input)”部分。怎么抢

    if(true == false) { $me = "Forever alone. :("; }
    if(true == true) { $me = "No longer alone. :}"; }
    if(false == false) { $me = ":{ - This is so Wrong."; }

不会被字符串(和 cmets 等 ofc)中的“{”和“}”字符误导?

我对正则表达式的了解非常有限,我很难做到这一点。 :/

【问题讨论】:

  • 要解析PHP代码吗?
  • 这行不通的原因与您无法使用正则表达式解析 HTML 的原因相同 - PHP 和 HTML 都不是常规语言
  • 我正在尝试创建/开发某种代码编辑器,它仅在方法内部限制编辑。
  • 用正则表达式来做这件事非常困难,你应该遍历字符,这样你就可以知道你在引用的块内处于什么状态......等等。因为这是一个嵌套问题……您需要知道何时回到原始嵌套级别。像 {....{{...}...}...} 这样的东西只是使用正则表达式的方式。

标签: php regex


【解决方案1】:

匹配括号是您不应该尝试使用正则表达式的典型示例之一(即使在字符串中没有括号,对于正则表达式来说也太复杂了)。

这是因为带有嵌套括号的(正式)语言不是正则的,而是由上下文无关语法表示的,这比简单的正则表达式要复杂得多。在非常高级的正则表达式上“不能计数到任意大的数字”,即它们无法识别哪个右括号属于哪个左括号(只要您允许括号的任意嵌套深度 - 如 PHP(至少在原则上))。

你最好使用一些支持上下文无关语法的工具,甚至是一些已经编写好的 PHP 解析器。

为了提取函数你自己,你可能应该只寻找关键字function(或其他表示功能块的关键字),然后转到左括号({)。然后,您可以逐个字符地查找匹配的右括号 (}),同时跟踪您当前是在字符串中还是在评论中。

但是,我不希望你自己手动完成这项任务,因为我可以想象处理所有可能的极端情况会很麻烦......

【讨论】:

  • 感谢您的信息。我会尝试一下正则表达式,直到某个时候。同时我也在找PHP解析器。
【解决方案2】:

我做了一个在大多数情况下都能通过的正则表达式,即使引号是反斜杠。这是一个示例脚本。我在正则表达式中提供了 cmets,但请注意,我需要对正则表达式中的每个 ' 进行反斜杠,因为我将其用作正则表达式本身的字符串分隔符。

正则表达式是递归的,因此它对括号嵌套的深度没有限制。但是,括号中不能有错误(即没有匹配的括号),但我猜这是合乎逻辑的。

$str =
'

public function my_method($my_input) {
    if(true == false) { $me = "Forever alone. :("; }
    if(true == true) { $me = "No longer alone. :}"; }
    if(true == true) { $me = \'No longer alone. :}\'; }
    if(true == true) { $me = \'No longer \\\' alone. :}\'; }
    if(false == false) { $me = ":{ - This is so Wrong."; }
}

public function my_method($my_input) {
    if(true == false) { $me = "Forever happy. :("; }
    if(true == true) { $me = "No longer happy. :}"; }
    if(true == true) { $me = \'No longer happy. :}\'; }
    if(true == true) { $me = \'No longer \\\' happy. :}\'; }
    if(false == false) { $me = ":{ - This is so Wrong."; }
}

';

preg_match_all(
   '/
      {                                # opening {
         (                             # matching parentheses
            (?:                        # non matching parentheses
               (?:                     # non matching parentheses
                  [^{}"\']+            # anything but { } " and \'
                  |                    # or
                  "                    # opening "
                     (?:               # non matching parentheses
                        [^"\\\]*       # anything but " and \
                        |              # or
                        \\\"           # a \ followed by a "
                     )*                # as often as possible
                  "                    # closing "
                  |                    # or
                  \'                   # opening \'
                     (?:               # non matching parentheses
                        [^\'\\\\]*     # anything but \' and \
                        |              # or
                        \\\\\'         # a \ followed by a \'
                     )*                # as often as possible
                  \'                   # closing \'
               )*                      # as often as possible
               |                       # or
               (?R)                    # repeat the whole pattern
            )*                         # as often as possible
         )                             # close matching parentheses
      }                                # closing }
   /xs',
   $str,
   $matches
);

print_r($matches);

【讨论】:

  • 我会尽快测试这个。哦,上帝,如果它有效,那就太好了!
  • 奇迹般地工作!谢谢。^^
【解决方案3】:

正则表达式不是解决此问题的正确工具 - 有关详细信息,请参阅 @phimuemue's answer..

你可以在你的脚本中使用PHP's own tokenizer。但是,它不会简单地为您提供“某些块内的内容”,而是块内的令牌。根据您想要做什么,您需要从令牌中重建源代码。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-01-26
    • 2015-12-19
    • 2019-02-07
    • 1970-01-01
    • 2017-04-07
    • 2016-12-18
    • 1970-01-01
    • 2011-02-28
    相关资源
    最近更新 更多