【问题标题】:Parse Tokens with Regex in PHP在 PHP 中使用正则表达式解析标记
【发布时间】:2010-11-17 15:04:13
【问题描述】:

我希望解析一个类似于下面的令牌文件以获取令牌名称/值对。令牌/值/嵌套关系已经定义,所以我不能改变令牌文件的制作方式。似乎上下文无关语法可能是最好的方法,但我没有编写或实施的经验。是否可以使用正则表达式来做到这一点?我对嵌套的多行标记(如 Master1、Servant2)没有任何运气。

;token1 = I am a top level single line token  
;token2 {  
    I am a top level  
    multiline line token  
}  

master1 {  
;servant1 = I am Master1, Servant1 single line token  
;servant2 {  
    I am Master1, Servant2.   
    A mulit line token.  
}  
;servant3 = I am Master1, Servant3  
}  
master2 {  
;servant1 = I am Master2, Servant1  
;servant2 {  
    I am Master2, Servant2  
A mulit line token.  
}  
;servant3 = I am Master2, Servant3  
}

【问题讨论】:

    标签: php regex token


    【解决方案1】:

    PHP 具有标记字符串的功能

    • strtok - 将字符串 (str) 拆分成更小的字符串 (tokens),每个 token 由 token 中的任何字符分隔。也就是说,如果你有一个像“This is an example string”这样的字符串,你可以通过使用空格字符作为标记将此字符串标记为单独的单词。

    【讨论】:

    • +1,大多数人推荐split,但由于该函数基于正则表达式,它的速度要慢得多,而且您可以在 strtok 中做一些事情,而 oyu 不能在爆炸等。跨度>
    【解决方案2】:

    这是一个相当简单的逐行解析器(我最初尝试为它编写一个正则表达式,但是在多行主控器的开头缺少前导 ; 确实使它变得更加困难(没有那个 @ 987654322@ 不见了,写起来还算容易)。我放弃了,写了这个):

    function getTokens($string) {
        $string = trim($string);;
        $lines = explode("\n", $string);
        $data = array();
        $key = '';
        $open = 0;
        $buffer = '';
        foreach ($lines as $line) {
            $line = trim($line);
            if (empty($line)) {
                continue;
            } elseif (strpos($line, '}') === 0) {
                $open--;
                if ($open == 0) {
                    $data[$key] = getTokens($buffer);
                    $buffer = '';
                } elseif ($open < 0) {
                    throw new Exception('Unmatched }');
                } else {
                    $buffer .= "\n" . $line;
                }
            } elseif ($open > 0) {
                if (strpos($line, '{') !== false) {
                    $open++;
                }
                $buffer .= "\n" . $line;
            } elseif ($line[0] == ';') {
                if (strpos($line, "=") !== false) {
                    list ($key, $value) = explode("=", $line, 2);
                    $key = trim(substr($key, 1));
                    $value = trim($value);
                    $data[$key] = $value;
                } elseif (strpos($line, "{") !== false) {
                    $open++;
                    list ($key, $value) = explode("{", $line, 2);
                    $key = trim(substr($key, 1));
                } else {
                    throw new Exception('Unmatched token ;');
                }
            } elseif (strpos($line, '{') !== false) {
                $open++;
                list ($key, $value) = explode("{", $line, 2);
                $key = trim($key);
            } else {
                $buffer .= "\n" . $line;
            }
        }
        if ($open > 0) {
            throw new Exception('Unmatched {');
        } elseif (empty($data) && !empty($buffer)) {
            return trim($buffer);
        }
        return $data;
    }
    

    当我输入你的字符串作为输入时,我得到:

    Array(
        "token1" => "I am a top level single line token",
        "token2" => "I am a top level
                        multiline line token",
        "master1" => Array(
            "servant1" => "I am Master1, Servant1 single line token",
            "servant2" => "I am Master1, Servant2.
                                A mulit line token.",
            "servant3" => "I am Master1, Servant3",
        ),
        "master2" => Array(
            "servant1" => "I am Master2, Servant1",
            "servant2" => "I am Master2, Servant2
                                A mulit line token.",
            "servant3" => "I am Master2, Servant3",
        ),
    )
    

    【讨论】:

    • 谢谢!那是完美的。我开始走同样的路。缺少前导分号也是让我丧命的原因!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多