查找PHP代码库中的所有字符串

时间:2009-02-21 00:08:34

标签: php string

我有几百万行的PHP代码库没有显示和逻辑的真正分离,我试图提取代码中表示的所有字符串以进行本地化。显示和逻辑的分离是一个长期目标,但是现在我只想本地化。

在代码中,字符串以PHP的每种可能格式表示,因此我需要一种理论(或实际)方法来解析整个源,并且至少在每个字符串所在的LOCATE处。当然,理想情况下,我会用函数调用替换每个字符串,例如

"this is a string"

将替换为

_("this is a string")

当然,我需要同时支持单{{}}和quote format。我不太关心的其他人,他们看起来很少,我可以手动改变它们。

另外,我当然不希望本地化数组索引。所以像

这样的字符串
$arr["value"]

不应该成为

$arr[_("value")]

任何人都可以帮助我开始这个吗?

3 个答案:

答案 0 :(得分:11)

您可以使用token_get_all()从PHP文件中获取所有令牌 e.g。

<?php

$fileStr = file_get_contents('file.php');

foreach (token_get_all($fileStr) as $token) {
    if ($token[0] == T_CONSTANT_ENCAPSED_STRING) {
        echo "found string {$token[1]}\r\n";
        //$token[2] is line number of the string
    }
}

你可以做一个非常脏的检查,它没有像以下那样用作数组索引:

$fileLines = file('file.php');

//inside the loop and if
$line = $fileLines[$token[2] - 1];
if (false === strpos($line, "[{$token[1]}]")) {
    //not an array index
}

但你真的很难做到这一点,因为有人可能写了你可能没想到的东西,例如:

$str = 'string that is not immediately an array index';
doSomething($array[$str]);

修改 正如Ant P所说,对于这个答案的第二部分而不是我的[ hack,你可能会更好地在周围的标记中寻找]strpos,这样的话:< / p>

$i = 0;
$tokens = token_get_all(file_get_contents('file.php'));
$num = count($tokens);
for ($i = 0; $i < $num; $i++) {
    $token = $tokens[$i];

    if ($token[0] != T_CONSTANT_ENCAPSED_STRING) {
        //not a string, ignore
        continue;
    }

    if ($tokens[$i - 1] == '[' && $tokens[$i + 1] == ']') {
        //immediately used as an array index, ignore
        continue; 
    }

    echo "found string {$token[1]}\r\n";
    //$token[2] is line number of the string
}

答案 1 :(得分:5)

在代码库中可能存在一些其他情况,除了关联数组之外,还可以通过自动搜索和替换来完全破解。

SQL查询:

$myname = "steve";
$sql = "SELECT foo FROM bar WHERE name = " . $myname;

间接变量引用。

$bar = "Hello, World"; // a string that needs localization
$foo = "bar"; // a string that should not be localized
echo($$foo);

SQL字符串操作。

$sql = "SELECT CONCAT('Greetings, ', firstname) as greeting from users where id = ?";

没有自动方式来过滤所有可能性。也许解决方案是编写一个应用程序,创建一个可能的字符串的“审核”队列,并在几行代码的上下文中突出显示每个字符串。然后,您可以浏览代码以确定它是否是需要本地化的字符串,并按一个键来本地化或忽略该字符串。

答案 2 :(得分:-3)

不要试图使用perl或grep过于聪明的命令行来解决这个问题,而应该编写一个程序来执行此操作:)

写一个perl / python / ruby​​ /无论什么脚本来搜索每个文件中的一对单引号或双引号。每次找到匹配项时,都会提示您将其替换为下划线函数,您可以告诉它执行此操作或跳到下一个。

在一个完美的世界里,你会写一些能为你做到这一切的东西,但最终可能会花费更少的时间,而且你会面临更少的错误。

伪:

for fname in yourBigFileList:
    create file handle for actual source file
    create temp file handle (like fname +".tmp" or something)
    for fline in fname:
        get quoted strings
        for qstring in quoted_strings:
            show it in context, i.e. the entire line of code.
            replace with _()?
                if Y, replace and write line to tmp file
                if N, just write that line to the tmp file
    close file handles
    rename it to current name + ".old"
    rename ".tmp" file to name of orignal file

我确信有更多的* nix-fu方法可以做到这一点,但是这种方法可以让你自己查看每个实例并做出决定。如果它是一百万行并且每一行包含一个字符串并且每一行需要1秒钟来评估,那么它将花费你大约270小时来完成整个事情......也许你应该忽略这篇文章:)