1

我正在构建一个任务(在 PHP 中),它读取我项目的所有文件以搜索 i18n 消息。我想检测这样的消息:

// Basic example
__('Show in English')  => Show in English
// Get the message and the name of the i18n file 
__("Show in English", array(), 'page') => Show in English, page
// Be careful of quotes
__("View Mary's Car", array()) => View Mary's Car
// Be careful of strings after the __() expression
__('at').' '.function($param) => at

适用于这些情况的正则表达式(考虑到其他一些情况)是:

__\(.*?['|\"](.*?)(?:['|\"][\.|,|\)])(?: *?array\(.*?\),.*?['|\"](.*?)['|\"]\)[^\)])?

但是,如果表达式在多行中,则它不起作用。我必须包括 dotail /s,但它破坏了以前的正则表达式,因为它不能很好地控制何时停止向前看:

// Detect with multiple lines
echo __('title_in_place', array(
    '%title%' => $place['title']
  ), 'welcome-user'); ?>    

有一件事可以解决问题并简化匹配开闭括号的正则表达式。因此,无论里面有什么__()或有多少括号,它都会“计算”打开的数量并期望关闭的数量。

可能吗?如何?非常感谢!

4

4 回答 4

2

是的。首先,这是简单嵌套括号(括号)的经典示例:

\(([^()]|(?R))*\)

或使用所有格量词的更快版本:

\(([^()]++|(?R))*\)

或(等效)原子分组:

\((?>[^()]+|(?R))*\)

但是你不能在这里使用:(?R) “匹配整个表达式”表达式,因为最外面的括号是特殊的(有两个前导下划线)。这是一个经过测试的脚本,它匹配(我认为)你想要的......

解决方案:使用组$1(递归)子程序调用:(?1)

<?php // test.php Rev:20120625_2200
$re_message = '/
    # match __(...(...)...) message lines (having arbitrary nesting depth).
    __\(                     # Outermost opening bracket (with leading __().
    (                        # Group $1: Bracket contents (subroutine).
      (?:                    # Group of bracket contents alternatives.
        [^()"\']++           # Either one or more non-brackets, non-quotes,
      | "[^"\\\\]*(?:\\\\[\S\s][^"\\\\]*)*"      # or a double quoted string,
      | \'[^\'\\\\]*(?:\\\\[\S\s][^\'\\\\]*)*\'  # or a single quoted string,
      | \( (?1) \)          # or a nested bracket (repeat group 1 here!).
      )*                    # Zero or more bracket contents alternatives.
    )                       # End $1: recursed subroutine.
    \)                      # Outermost closing bracket.
    .*                      # Match remainder of line following __()
    /mx';
$data = file_get_contents('testdata.txt');
$count = preg_match_all($re_message, $data, $matches);
printf("There were %d __(...) messages found.\n", $count);
for ($i = 0; $i < $count; ++$i) {
    printf("  message[%d]: %s\n", $i + 1, $matches[0][$i]);
}
?>

请注意,此解决方案将平衡括号(在 " __(...)" 构造内)处理到任意深度(仅受主机内存限制)。它还正确处理 " __(...)" 中的引用字符串,并忽略可能出现在这些引用字符串中的任何括号。祝你好运。*

于 2012-06-26T00:38:28.673 回答
1

正则表达式无法匹配平衡括号(除非您使用具有非标准非正则扩展名的引擎,但即便如此,这仍然是一个坏主意,并且难以维护)。

您可以使用正则表达式来查找包含潜在匹配项的行,然后逐个字符地遍历字符串,计算开括号和右括号的数量,直到找到匹配的右括号的索引。

于 2012-06-25T16:28:57.650 回答
1

对我来说使用这样的表达

(\(([^()]+)\))

我试着找到它

 * 1) (1+2)
 * 2) (1+2)+(3+2)
 * 3) (IF 1 THEN 1 ELSE 0) > (IF 2 THEN 1 ELSE 1)
 * 4) (1+2) -(4+ (3+2))
 * 5) (1+2) -((4+ (3+2)-(6-7)))
于 2017-01-12T13:43:24.127 回答
0

我知道实现这一点的唯一方法是使用平衡的组定义。这是 .NET 风格的正则表达式的一个特性,在这篇文章中有很好的解释。

正如 Qtax 所指出的,这可以在 PCRE 中完成,(?R)他们的文档中所述。

或者这也可以通过编写自定义解析器来完成。基本上,这个想法是在ParenthesesCount从左到右解析时维护一个名为的变量。每次看到都会增加,ParenthesesCount每次看到(都会减少)。我最近编写了一个以这种方式处理嵌套括号的解析器。

于 2012-06-25T16:34:39.353 回答