为什么grep不能使用正则表达式?

时间:2015-02-17 09:56:52

标签: php regex bash

我有一个正则表达式来查找文件中的函数。

See how expression perfectly works in PHP

如果我尝试使用来自控制台的grep运行相同的正则表达式,我会收到错误:

grep -rP "(_t\s*\(\s*([\'\"])(\d+)\2\s*,\s*([\'\"])(.*?)(?<!\\)\4\s*(?(?=,)[^\)]*\s*\)|\)))" application scripts library public data | sort -n | uniq

grep: unrecognized character after (?<

看起来grep无法处理这部分正则表达式(?<!\\),这对我很重要。

有人可以建议如何修改正则表达式以使grep与它一起使用吗?

编辑:     字符串:_t('123', 'pcs.', '', $userLang) . $data['ticker'] . ' (' . $data['security_name'] . ')

需要找到:

  1. 功能索引(&#39; 123&#39;)

  2. 功能中的文字(&#39; pcs。&#39;)

  3. 功能本身

    > _t('123', 'pcs.', '', $userLang)
    

2 个答案:

答案 0 :(得分:3)

执行我在评论中所说的内容可以解决您的问题(使用链接中的数据):

$ cat file
_t('123', 'шт.', '', $userLang)  . $data['ticker'] . ' (' . $data['security_name'] . ')
$ grep -P '(_t\s*\(\s*(['"'"'"])(\d+)\2\s*,\s*(['"'"'"])(.*?)(?<!\\)\4\s*(?(?=,)[^\)]*\s*\)|\)))' file
_t('123', 'шт.', '', $userLang)  . $data['ticker'] . ' (' . $data['security_name'] . ')

这里的技巧是在整个正则表达式周围使用单引号,然后每当你想要单引号时,执行'"'"',这意味着&#34;关闭原始字符串,在双引号内添加单引号,然后打开一个新的单引号字符串&#34;。根据{{​​3}}的建议,另一种方法是使用'\'',即关闭原始字符串,添加转义'并打开新字符串。

使用单引号可防止bash将!解释为历史记录扩展。正如glglgl上面提到的那样另一种选择是使用set +o history禁用该行为。

作为一个建议,如果你想要捕获正则表达式的不同部分(并且你已经在grep中使用了PCRE模式),你可以改用Perl:

$ perl -lne '/(_t\s*\(\s*(['\''"])(\d+)\2\s*,\s*(['\''"])(.*?)(?<!\\)\4\s*(?(?=,)[^\)]*\s*\)|\)))/ && print "group 1: $1\ngroup 3: $3\n group 5: $5"' file
group 1: _t('123', 'шт.', '', $userLang)
group 3: 123
group 5: шт.

答案 1 :(得分:0)

我强烈建议使用tokenizer extension来解析PHP文件。这是因为解析编程语言需要有状态解析器,单个正则表达式是无状态的,因此无法提供。

以下是一个如何从PHP源文件中提取函数名称的示例,也可以跟踪函数调用:

$source = file_get_contents('some.php');

$tokens = token_get_all($source);
for($i = 0; $i < count($tokens); $i++) {
    $token = $tokens[$i];
    if(!is_string($token)) {
        if($token[0] === T_FUNCTION) {
            // skip whitespace between the keyword 'function' 
            // and the function's name
            $i+=2;
            // Avoid to print the opening brackets of a closure
            if($tokens[$i][0] === T_STRING) {
                echo $tokens[$i][1] . PHP_EOL;
            }
        }
    }   
}

在评论中你告诉你还要解析html,js文件。我建议使用DOM / JS解析器。