PHP:标记化,使用正则表达式(主要是那里)

PHP: tokenizing, using a regular Expression (mostly there)

我想标记格式化字符串(非常类似于 printf),我想我只遗漏了一点点:

我在 the regExp simulator 中走得很远。这看起来应该这样做:

²更新:现在使用 # 而不是 %。 (减少windows命令行参数的麻烦)

这并不可怕,如果你关注三个部分,通过管道连接(非此即彼),那么基本上它只是三场比赛。因为我想从头到尾匹配,所以我将东西包裹在 /^...%/ 中并被一个可能重复 1 次或多次的非匹配组 (?:... 包围:

$exp = '/^(?:(%\d*[ctYymd]+)|([^$%]+)|(\$\d))+$/'; 

我的来源仍然没有提供:

$exp = '/^(?:(%\d*[ctYymd]+)|([^$%]+)|(\$\d))+$/';
echo "expression: $exp \n";

$tests = [
        '###%04d_Ball0n%02d',
        '%03d_Ball0n%02x%03d_Ball0n%02d',
        '%3d_Ball0n%02d',
    ];

foreach ( $tests as $test )
{
    echo "teststring: $test\n";
    if( preg_match( $exp, $test, $tokens) )
    {
        array_shift($tokens);
        foreach ( $tokens as $token )
            echo "\t\t'$token'\n";
    }
    else
        echo "not valid.";
} // foreach

我得到了结果,但是:匹配顺序不对。第一个 %[number][letter] 永远不会匹配,因此其他匹配双:

expression: /^((%\d*[ctYymd]+)|([^$%]+)|($\d))+$/ 
teststring: ###%04d_Ball0n%02d
        ''
        '%02d'
        '_Ball0n'
        ''
teststring: %03d_Ball0n%02x%03d_Ball0n%02d
not valid.teststring: %3d_Ball0n%02d
        '%02d'
        '%02d'
        '_Ball0n'
teststring: %d_foobardoo
        '_foobardoo'
        '%d'
        '_foobardoo'
teststring: Ball0n%02dHamburg%d
        '%d'
        '%d'
        'Hamburg'

解决方案(由 OP 编辑​​):我使用了两个细微的变化(仅关于“包装”):首先用于验证,然后用于标记化:

#\d*[ctYymd]+|$\d+|[^#$]+

RegEx Demo

代码:

$core = '#\d*[ctYymd]+|$\d+|[^#$]+';
$expValidate = '/^('.$core.')+$/m';
$expTokenize = '/('.$core.')/m';

$tests = [
        '#3d-',
        '#3d-ABC',
        '***#04d_Ball0n#02d',
        '#03d_Ball0n#02x$AwrongDollar',
        '#3d_Ball0n#02d',
        'Badstring#02xWrongLetterX'
    ];

foreach ( $tests as $test )
{
    echo "teststring: [$test]\n";

    if( ! preg_match_all( $expValidate, $test) )
    {
        echo "not valid.\n";
        continue;
    }
    if( preg_match_all( $expTokenize, $test, $tokens) ) {
        foreach ( $tokens[0] as $token )
            echo "\t\t'$token'\n";
    }

} // foreach

输出:

teststring: [#3d-]
        '#3d'
        '-'
teststring: [#3d-ABC]
        '#3d'
        '-ABC'
teststring: [***#04d_Ball0n#02d]
        '***'
        '#04d'
        '_Ball0n'
        '#02d'
        ''
teststring: [#03d_Ball0n#02x$AwrongDollar]
not valid.
teststring: [#3d_Ball0n#02d]
        '#3d'
        '_Ball0n'
        '#02d'
teststring: [Badstring#02xWrongLetterX]
not valid.