Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/288.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/regex/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 正则表达式解析define()内容,可能吗?_Php_Regex - Fatal编程技术网

Php 正则表达式解析define()内容,可能吗?

Php 正则表达式解析define()内容,可能吗?,php,regex,Php,Regex,我对regex很陌生,这对我来说太高级了。所以我在问这里的专家 问题 我想从php define()中检索常量/值 基本上,我希望正则表达式能够返回常量的名称,以及上面一行中常量的值。只有文本和值。这可能吗 为什么我需要它?我正在处理语言文件,我想得到所有的对(名称、值),并将它们放入数组中。我用str_replace()和trim()等工具成功地实现了这一点。。但这条路很长,我相信使用单行正则表达式可以使它变得更容易 注意:该值也可能包含转义单引号。例如: DEFINE('TEXT', 'J\

我对regex很陌生,这对我来说太高级了。所以我在问这里的专家

问题 我想从php define()中检索常量/值

基本上,我希望正则表达式能够返回常量的名称,以及上面一行中常量的值。只有文本和值。这可能吗


为什么我需要它?我正在处理语言文件,我想得到所有的对(名称、值),并将它们放入数组中。我用str_replace()和trim()等工具成功地实现了这一点。。但这条路很长,我相信使用单行正则表达式可以使它变得更容易

注意:该值也可能包含转义单引号。例如:

DEFINE('TEXT', 'J\'ai');
我希望我没有要求太复杂的事情


关于

您可能不需要过分考虑正则表达式的复杂性-类似这样的东西可能就足够了

 /DEFINE\('(.*?)',\s*'(.*)'\);/
下面是一个PHP示例,展示了如何使用它

$lines=file("myconstants.php");
foreach($lines as $line) {
    $matches=array();
    if (preg_match('/DEFINE\(\'(.*?)\',\s*\'(.*)\'\);/i', $line, $matches)) {
        $name=$matches[1];
        $value=$matches[2];

        echo "$name = $value\n";
    }

}

这是可能的,但我宁愿使用。但是要确保所有的翻译都有共同点(比如所有以T开头的翻译),这样就可以将它们与其他常量区分开来。

尝试使用此正则表达式查找
定义
调用:

 /\bdefine\(\s*("(?:[^"\\]+|\\(?:\\\\)*.)*"|'(?:[^'\\]+|\\(?:\\\\)*.)*')\s*,\s*("(?:[^"\\]+|\\(?:\\\\)*.)*"|'(?:[^'\\]+|\\(?:\\\\)*.)*')\s*\);/is
因此:


对于任何一种基于语法的解析,正则表达式通常都是一个糟糕的解决方案。即使是smple语法(比如算术)也有嵌套,正则表达式就是在嵌套(尤其是)的基础上崩溃的

幸运的是,PHP为您提供了一个更好得多的解决方案,它允许您通过访问PHP解释器使用的相同词法分析器。给它一个PHP代码的字符流,它将把它解析成记号(“lexemes”),你可以用一个非常简单的方法对它进行一些简单的解析

运行这个程序(它作为test.php运行,所以它会自己尝试)。该文件故意格式化不好,因此您可以看到它可以轻松地处理该文件

<?
    define('CONST1', 'value'   );
define   (CONST2, 'value2');
define(   'CONST3', time());
  define('define', 'define');
    define("test", VALUE4);
define('const5', //

'weird declaration'
)    ;
define('CONST7', 3.14);
define ( /* comment */ 'foo', 'bar');
$defn = 'blah';
define($defn, 'foo');
define( 'CONST4', define('CONST5', 6));

header('Content-Type: text/plain');

$defines = array();
$state = 0;
$key = '';
$value = '';

$file = file_get_contents('test.php');
$tokens = token_get_all($file);
$token = reset($tokens);
while ($token) {
//    dump($state, $token);
    if (is_array($token)) {
        if ($token[0] == T_WHITESPACE || $token[0] == T_COMMENT || $token[0] == T_DOC_COMMENT) {
            // do nothing
        } else if ($token[0] == T_STRING && strtolower($token[1]) == 'define') {
            $state = 1;
        } else if ($state == 2 && is_constant($token[0])) {
            $key = $token[1];
            $state = 3;
        } else if ($state == 4 && is_constant($token[0])) {
            $value = $token[1];
            $state = 5;
        }
    } else {
        $symbol = trim($token);
        if ($symbol == '(' && $state == 1) {
            $state = 2;
        } else if ($symbol == ',' && $state == 3) {
            $state = 4;
        } else if ($symbol == ')' && $state == 5) {
            $defines[strip($key)] = strip($value);
            $state = 0;
        }
    }
    $token = next($tokens);
}

foreach ($defines as $k => $v) {
    echo "'$k' => '$v'\n";
}

function is_constant($token) {
    return $token == T_CONSTANT_ENCAPSED_STRING || $token == T_STRING ||
        $token == T_LNUMBER || $token == T_DNUMBER;
}

function dump($state, $token) {
    if (is_array($token)) {
        echo "$state: " . token_name($token[0]) . " [$token[1]] on line $token[2]\n";
    } else {
        echo "$state: Symbol '$token'\n";
    }
}

function strip($value) {
    return preg_replace('!^([\'"])(.*)\1$!', '$2', $value);
}
?>
这基本上是一个查找模式的有限状态机:

function name ('define')
open parenthesis
constant
comma
constant
close parenthesis
在PHP源文件的词法流中,并将这两个常量视为(名称、值)对。在此过程中,它处理嵌套的define()语句(根据结果),忽略空格和注释,并跨多行工作

注意:我已经仔细考虑过了,让它忽略函数和变量是常量名称或值的情况,但您可以根据需要扩展它

还值得指出的是,PHP在字符串方面非常宽容。可以使用单引号、双引号或(在某些情况下)完全不使用引号来声明它们。这可能(正如Gumbo所指出的)是一个对常数的模糊引用,而您无法知道它是哪一个(无论如何也无法保证),这给您带来了以下好处:

  • 忽略该样式的字符串(T_字符串)
  • 查看是否已使用该名称声明了常量,并替换其值。但是,您无法知道调用了哪些其他文件,也无法处理任何有条件创建的定义,因此您无法确定任何内容是否为常量,也无法确定它具有什么值;或
  • 您可以接受这些可能是常量(这不太可能),并将它们视为字符串

  • 就我个人而言,我会选择(1)然后(3)。

    不是所有文本问题都应该用regexp解决,所以我建议您说明您想要实现什么,而不是如何实现

    因此,与其使用php的解析器,或者使用完全不可调试的正则表达式,不如编写一个简单的解析器

    <?php
    
    $str = "define('nam\\'e', 'va\\\\\\'lue');\ndefine('na\\\\me2', 'value\\'2');\nDEFINE('a', 'b');";
    
    function getDefined($str) {
        $lines = array();
        preg_match_all('#^define[(][ ]*(.*?)[ ]*[)];$#mi', $str, $lines);
    
        $res = array();
        foreach ($lines[1] as $cnt) {
            $p = 0;
            $key = parseString($cnt, $p);
            // Skip comma
            $p++;
            // Skip space
            while ($cnt{$p} == " ") {
                $p++;
            }
            $value = parseString($cnt, $p);
    
            $res[$key] = $value;
        }
    
        return $res;
    }
    
    function parseString($s, &$p) {
        $quotechar = $s[$p];
        if (! in_array($quotechar, array("'", '"'))) {
            throw new Exception("Invalid quote character '" . $quotechar . "', input is " . var_export($s, true) . " @ " . $p);
        }
    
        $len = strlen($s);
        $quoted = false;
        $res = "";
    
        for ($p++;$p < $len;$p++) {
            if ($quoted) {
                $quoted = false;
                $res .= $s{$p};
            } else {
                if ($s{$p} == "\\") {
                    $quoted = true;
                    continue;
                }
                if ($s{$p} == $quotechar) {
                    $p++;
                    return $res;
                }
                $res .= $s{$p};
            }
        }
    
        throw new Exception("Premature end of line");
    }
    
    var_dump(getDefined($str));
    

    那个么非文字值(如
    define('NOW',time())
    )呢?我正在处理的语言文件只包含两边单引号中的文本。常量名称和值。所以名称和值始终是固定字符串?但这样做可能需要编辑太多行?他们没有共同之处。。所以我想我可以用一个正则表达式这就是为什么我叫保罗。这只检查模式定义('text','value'),对吗?--我的意思是如果我想收集下一个文本和值。。我该怎么做?工作得很有魅力!~救了我很多!犯错误这在任何琐碎的变化上都是失败的,比如定义(“废话”,“foo”)。此外,在除现有间距以外的任何间距上,定义跨越多条直线、heredocs和foth。这甚至在定义('const','foo')时失败;克莱特斯,我喜欢这个,因为它很短,非常适合我的需要。假设翻译总是在单引号中,并且总是字符串。。无论如何,要使它在定义('constant','value')时不会失败?我的意思是如果空间被遗漏了?如果常数2已经是一个常数呢<代码>定义('foo','bar');定义(foo,'baz')=>foo='bar',bar='baz'常量2是一个T_字符串常量。通过额外的检查,您可以检查是否获得T_字符串常量,然后对其使用is_defined(),获取值,或者,如果未定义,则将其视为字符串(与PHP一样)。“CONST2是T_字符串常量。”–哦,我忘了:它是PHP.)我印象深刻,它返回的输出就像书上说的那样。目前,这两种解决方案都很好,并且都在发挥作用。谢谢你们两位
    <?
        define('CONST1', 'value'   );
    define   (CONST2, 'value2');
    define(   'CONST3', time());
      define('define', 'define');
        define("test", VALUE4);
    define('const5', //
    
    'weird declaration'
    )    ;
    define('CONST7', 3.14);
    define ( /* comment */ 'foo', 'bar');
    $defn = 'blah';
    define($defn, 'foo');
    define( 'CONST4', define('CONST5', 6));
    
    header('Content-Type: text/plain');
    
    $defines = array();
    $state = 0;
    $key = '';
    $value = '';
    
    $file = file_get_contents('test.php');
    $tokens = token_get_all($file);
    $token = reset($tokens);
    while ($token) {
    //    dump($state, $token);
        if (is_array($token)) {
            if ($token[0] == T_WHITESPACE || $token[0] == T_COMMENT || $token[0] == T_DOC_COMMENT) {
                // do nothing
            } else if ($token[0] == T_STRING && strtolower($token[1]) == 'define') {
                $state = 1;
            } else if ($state == 2 && is_constant($token[0])) {
                $key = $token[1];
                $state = 3;
            } else if ($state == 4 && is_constant($token[0])) {
                $value = $token[1];
                $state = 5;
            }
        } else {
            $symbol = trim($token);
            if ($symbol == '(' && $state == 1) {
                $state = 2;
            } else if ($symbol == ',' && $state == 3) {
                $state = 4;
            } else if ($symbol == ')' && $state == 5) {
                $defines[strip($key)] = strip($value);
                $state = 0;
            }
        }
        $token = next($tokens);
    }
    
    foreach ($defines as $k => $v) {
        echo "'$k' => '$v'\n";
    }
    
    function is_constant($token) {
        return $token == T_CONSTANT_ENCAPSED_STRING || $token == T_STRING ||
            $token == T_LNUMBER || $token == T_DNUMBER;
    }
    
    function dump($state, $token) {
        if (is_array($token)) {
            echo "$state: " . token_name($token[0]) . " [$token[1]] on line $token[2]\n";
        } else {
            echo "$state: Symbol '$token'\n";
        }
    }
    
    function strip($value) {
        return preg_replace('!^([\'"])(.*)\1$!', '$2', $value);
    }
    ?>
    
    'CONST1' => 'value'
    'CONST2' => 'value2'
    'CONST3' => 'time'
    'define' => 'define'
    'test' => 'VALUE4'
    'const5' => 'weird declaration'
    'CONST7' => '3.14'
    'foo' => 'bar'
    'CONST5' => '6'
    
    function name ('define')
    open parenthesis
    constant
    comma
    constant
    close parenthesis
    
    <?php
    
    $str = "define('nam\\'e', 'va\\\\\\'lue');\ndefine('na\\\\me2', 'value\\'2');\nDEFINE('a', 'b');";
    
    function getDefined($str) {
        $lines = array();
        preg_match_all('#^define[(][ ]*(.*?)[ ]*[)];$#mi', $str, $lines);
    
        $res = array();
        foreach ($lines[1] as $cnt) {
            $p = 0;
            $key = parseString($cnt, $p);
            // Skip comma
            $p++;
            // Skip space
            while ($cnt{$p} == " ") {
                $p++;
            }
            $value = parseString($cnt, $p);
    
            $res[$key] = $value;
        }
    
        return $res;
    }
    
    function parseString($s, &$p) {
        $quotechar = $s[$p];
        if (! in_array($quotechar, array("'", '"'))) {
            throw new Exception("Invalid quote character '" . $quotechar . "', input is " . var_export($s, true) . " @ " . $p);
        }
    
        $len = strlen($s);
        $quoted = false;
        $res = "";
    
        for ($p++;$p < $len;$p++) {
            if ($quoted) {
                $quoted = false;
                $res .= $s{$p};
            } else {
                if ($s{$p} == "\\") {
                    $quoted = true;
                    continue;
                }
                if ($s{$p} == $quotechar) {
                    $p++;
                    return $res;
                }
                $res .= $s{$p};
            }
        }
    
        throw new Exception("Premature end of line");
    }
    
    var_dump(getDefined($str));
    
    array(3) {
      ["nam'e"]=>
      string(7) "va\'lue"
      ["na\me2"]=>
      string(7) "value'2"
      ["a"]=>
      string(1) "b"
    }