Perl在CLI上搜索/替换捕获组

时间:2013-02-01 07:51:55

标签: regex perl

PHP的strlen()函数不支持UTF-8,因此我想将strlen()的每个用法与其UTF-8识别对应项交换:mb_strlen()。但是,mb_strlen()需要一个额外的参数:

$length = strlen($someString);
$length = mb_strlen($someString, 'UTF-8');

如果没有第二个参数,一个简单的Perl正则表达式将处理交换:

$ find . -name '*' -print0 | xargs -0 perl -pi -e 's/strlen/mb_strlen/g'

我尝试使用捕获组和反向引用,但VIM风格的语法要么不支持(在最近的Ubuntu上),要么我无法弄明白。我已经尝试了几种变体而没有成功:

$ find . -name '*' -print0 | xargs -0 perl -pi -e 's/strlen\((\.*)\)/mb_strlen\($1, "UTF-8"\)/g'

此外,trim()内部可能存在strlen()等函数,所以我必须让这个贪婪,但我不确定贪婪的运算符应该在哪里。这个正则表达式应该如何编写?

4 个答案:

答案 0 :(得分:1)

这比首次出现时更难。你要么:

  1. 正确解析表达式,包括表达式的多行版本。
  2. 作弊
  3. 我会去作弊。

    大多数strlen()调用都非常简单,剩下的少数几个可以手动替换。你在某种版本控制下做这件事,不是你:

    简单:strlen(“foo”),strlen($ bar)

    # Match simple quoted strings - no embedded quotes
    s/strlen\((["'][^"']*["'])\)/mb_strlen($1, 'UTF-8')/g
    # Match simple variables - no method calls etc
    s/strlen\((\$\w+)\)/mb_strlen($1, 'UTF-8')/g
    

    处理数组变量,函数和方法调用以及其他表达式变得更复杂,但是看看在这两个基本替换后剩下多少个。

答案 1 :(得分:0)

通过指定\.*,正则表达式将匹配0个或更多文字'.'

省略\

后尝试一下
s/strlen\((.*)\)/mb_strlen($1, "UTF-8")/g
           ^              ^           ^
           NO BACKSLASH   NO BACKSLASH NEEDED
                          AS THIS IS TREATED AS
                          A STRING AND NOT A REGEX

另外,首先尝试不使用-i标记进行测试,以确保您对替换感到满意,否则您的文件将在原位进行修改。

答案 2 :(得分:0)

在一般情况下使用简单的正则表达式无法解决您的问题。请考虑以下示例:

if (strlen($var) > 0)

$total_length = strlen($thing1) + strlen($thing2);

strlen($var);   #Don't use trim() here because it was already trimmed.

some_other_function(strlen($foo) + 2);

这些都不适用于你的正则表达式,因为.*将贪婪地捕获所有内容直到行中的最后一个右括号。正确执行此操作的唯一方法是检查平衡括号,这在正则表达式中是非常重要的(尽管在技术上可以使用Perl的扩展正则表达式功能,但这并非易事)。

如果您认为上述情况不会遇到很多情况,那么只需使用其他建议的解决方案之一并检查错误。或者你可以这样做来捕获其中没有任何括号的所有简单案例:

s/\bstrlen\(([^()]*)\)/mb_strlen($1, "UTF-8")/g

(注意,我还添加了\b以确保它从单词边界开始。这将阻止您双重替换已经mb_strlen的内容

但是,有一个简单快速的黑客解决方案应该适用于所有情况:创建自己的PHP函数my_mb_strlen,或者其他什么,在添加时调用mb_strlen附加论点。然后,您可以执行更简单的搜索并仅替换函数名称,将strlen替换为my_mb_strlen

答案 3 :(得分:0)

find . -type f|xargs perl -pi -e 's/strlen\(([^\)]*)\)/mb_strlen($1,'UTF_8')/g'