0

因此,我正在使用 Shunting-Yard 算法从 XML 字符串中处理一些数学运算。诀窍是我想允许使用逗号分隔列表生成随机值。例如...

( ( 3 + 4 ) * 12 ) * ( 2, 3, 4, 5 ) )

我已经有一个基本的 Shutting-Yard 处理器在工作。但我想在处理表达式之前预处理字符串以从列表中随机选择一个值。这样我最终可能会得到:

( ( 3 + 4 ) * 12 ) * 4 )

就我的理解而言,Shunting-Yard 的设置已经相当复杂,所以我很犹豫是否尝试改变它来处理这个问题。用错误检查来处理这个问题听起来像是一场噩梦。因此,我假设事先寻找这种模式是有意义的?我正在考虑使用正则表达式,但我不是“那些”人之一......虽然我希望我是......虽然我找到了一些例子,但我不确定如何修改它们先检查括号?我也不相信这将是最好的解决方案。

附带说明一下,如果解决方案是正则表达式,它也应该能够匹配逗号列表中的字符串(只有字符,没有符号),因为我将在我的 Shunting-Yard 实现中处理特定字符串的值。

提前感谢您的想法。

4

1 回答 1

1

使用两个正则表达式很容易解决这个问题。应用于整个文本的第一个正则表达式匹配每个带括号的逗号分隔值列表。第二个正则表达式,应用于每个先前匹配的列表,匹配列表中的每个值。这是一个 PHP 脚本,它具有一个函数,给定具有多个列表的输入文本,将每个列表替换为随机选择的其中一个值:

<?php // test.php 20110425_0900

function substitute_random_value($text) {
    $re = '/
        # Match parenthesized list of comma separated words.
        \(           # Opening delimiter.
        \s*          # Optional whitespace.
        \w+          # required first value.
        (?:          # Group for additional values.
          \s* , \s*  # Values separated by a comma, ws
          \w+        # Next value.
        )+           # One or more additional values.
        \s*          # Optional whitespace.
        \)           # Closing delimiter.
        /x';
    // Match each parenthesized list and replace with one of the values.
    $text = preg_replace_callback($re, '_srv_callback', $text);
    return $text;
}
function _srv_callback($matches_paren) {
    // Grab all word options in parenthesized list into $matches.
    $count = preg_match_all('/\w+/', $matches_paren[0], $matches);
    // Randomly pick one of the matches and return it.
    return $matches[0][rand(0, $count - 1)];
}

// Read input text
$data_in = file_get_contents('testdata.txt');

// Process text multiple times to verify random replacements.
$data_out  = "Run 1:\n". substitute_random_value($data_in);
$data_out .= "Run 2:\n". substitute_random_value($data_in);
$data_out .= "Run 3:\n". substitute_random_value($data_in);

// Write output text
file_put_contents('testdata_out.txt', $data_out);

?>

substitute_random_value()函数调用 PHPpreg_replace_callback()函数,该函数将每个列表匹配并替换为列表中的一个值。它调用_srv_callback()随机选择一个值并将其作为替换值返回的函数。

给定这个输入测试数据(testdata.txt):

( ( 3 + 4 ) * 12 ) * ( 2, 3, 4, 5 ) )
( ( 3 + 4 ) * 12 ) * ( 12, 13) )
( ( 3 + 4 ) * 12 ) * ( 22, 23, 24) )
( ( 3 + 4 ) * 12 ) * ( 32, 33, 34, 35 ) )

这是脚本的一个示例运行的输出:

Run 1:
( ( 3 + 4 ) * 12 ) * 5 )
( ( 3 + 4 ) * 12 ) * 13 )
( ( 3 + 4 ) * 12 ) * 22 )
( ( 3 + 4 ) * 12 ) * 35 )
Run 2:
( ( 3 + 4 ) * 12 ) * 3 )
( ( 3 + 4 ) * 12 ) * 12 )
( ( 3 + 4 ) * 12 ) * 22 )
( ( 3 + 4 ) * 12 ) * 33 )
Run 3:
( ( 3 + 4 ) * 12 ) * 3 )
( ( 3 + 4 ) * 12 ) * 12 )
( ( 3 + 4 ) * 12 ) * 23 )
( ( 3 + 4 ) * 12 ) * 32 )

请注意,此解决方案用于\w+匹配由“单词”字符组成的值,即 [A-Za-z0-9_]。如果这不符合您的要求,则可以轻松更改。

编辑:这是该substitute_random_value()函数的 Javascript 版本:

function substitute_random_value(text) {
    // Replace each parenthesized list with one of the values.
    return text.replace(/\(\s*\w+(?:\s*,\s*\w+)+\s*\)/g,
        function (m0) {
           // Capture all word values in parenthesized list into values.
            var values = m0.match(/\w+/g);
            // Randomly pick one of the matches and return it.
            return values[Math.floor(Math.random() * values.length)];
        });
}
于 2011-04-25T15:51:53.803 回答