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

在PHP代码库中查找所有字符串,php,string,Php,String,我有几百万行PHP代码库,没有真正的显示和逻辑分离,我正试图提取代码中表示的所有字符串,以便本地化。显示和逻辑的分离是一个长期目标,但现在我只想能够本地化 在代码中,字符串以PHP的各种可能格式表示,因此我需要一种理论(或实际)方法来解析整个源代码,至少要找到每个字符串所在的位置。当然,在理想情况下,我会用一个函数调用来替换每个字符串 "this is a string" “这是一个字符串” 将被替换为 _("this is a string") _(“这是一个字符串”) 当然,我需要支持单人和

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

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

"this is a string" “这是一个字符串” 将被替换为

_("this is a string") _(“这是一个字符串”) 当然,我需要支持单人和双人。其他我不太关心的,它们很少出现,我可以手动更改它们

当然,我也不想本地化数组索引。所以弦像

$arr["value"] $arr[“价值”] 不应该成为

$arr[_("value")] $arr[uU2;(“价值”)] 有谁能帮我开始这方面的工作吗?

您可以使用它从PHP文件中获取所有令牌 e、 g

但你会很难做到这一点,因为可能有人写了一些你可能不期望的东西,例如:

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

编辑 正如Ant P所说,对于这个答案的第二部分,您最好在周围的令牌中查找
[
]
,而不是我的
strpos
hack,类似这样的东西:

$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
}
$i=0;
$tokens=token_get_all(file_get_contents('file.php');
$num=计数($tokens);
对于($i=0;$i<$num;$i++){
$token=$tokens[$i];
if($token[0]!=T\u常量\u封装的\u字符串){
//不是字符串,忽略
继续;
}
如果($tokens[$i-1]='['&&&$tokens[$i+1]==']')){
//立即用作数组索引,忽略
继续;
}
echo“找到字符串{$token[1]}\r\n”;
//$token[2]是字符串的行号
}

不要试图通过使用perl或grep的过于聪明的命令行破解来解决这个问题,您应该编写一个程序来实现这一点:)

编写一个perl/python/ruby/anywhere脚本,在每个文件中搜索一对单引号或双引号。每次它找到匹配项时,都会提示您用下划线函数替换它,您可以告诉它这样做,也可以跳到下一个

在一个完美的世界里,你会写一些能帮你完成一切的东西,但这最终可能会花更少的时间,你会面临更少的错误

伪:

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

我相信有一种更简单的方法可以做到这一点,但这种方法可以让你自己查看每个实例并做出决定。如果有一百万行,每一行都包含一个字符串,每一行都需要1秒的时间来计算,那么整个过程大约需要270个小时。。。也许您应该忽略这篇文章:)

代码库中可能存在一些其他情况,除了关联数组之外,您还可以通过执行自动搜索和替换来彻底打破这些情况

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 = ?";

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

唯一的问题是,对于$\u SESSION['logsession'],它实际上会给我找到的字符串'logsession',这当然不是我想要本地化的字符串。@tomhaigh:我会进行第二次投票,如果可以的话。脱帽致敬。@ray:通过在周围标记的上下文中查看字符串,您可能可以确定该字符串是用作字符串还是用作数组ID。不过我自己还没试过。很抱歉,这个答案唯一相关的部分是你的伪代码中的“get quoted strongs”,你没有提到,所以我不知道你为什么给出这个答案。
$bar = "Hello, World"; // a string that needs localization
$foo = "bar"; // a string that should not be localized
echo($$foo);
$sql = "SELECT CONCAT('Greetings, ', firstname) as greeting from users where id = ?";