Обработка списка, разделенного запятыми, перед маневровым двором - PullRequest
0 голосов
/ 25 апреля 2011

Итак, я обрабатываю некоторые математические операции из XML-строк, используя алгоритм Shunting-Yard. Хитрость заключается в том, что я хочу разрешить генерацию случайных значений с помощью списков через запятую. Например ...

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

У меня уже работает базовый процессор Shunting-Yard. Но я хочу предварительно обработать строку, чтобы случайным образом выбрать одно из значений в списке перед обработкой выражения. Так что я мог бы в конечном итоге:

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

Установка Shunting-Yard уже довольно сложна, насколько мне известно, поэтому я не решаюсь изменить ее, чтобы справиться с этим. Обработка этого с проверкой ошибок звучит как кошмар. Таким образом, я полагаю, что имеет смысл поискать этот шаблон заранее? Я подумывал об использовании регулярного выражения, но я не один из "тех" людей ... хотя я бы хотел, чтобы я был ... и хотя я нашел примеров , я не уверен, как я мог бы изменить их, чтобы сначала проверить скобки? Я также не уверен, что это будет лучшим решением.

В качестве примечания: если решение является регулярным выражением, оно должно быть в состоянии сопоставлять строки (только символы, без символов) в списке запятых, так как я буду обрабатывать для конкретных строк значения в моем Shunting- Реализация двора.

Спасибо за ваши мысли заранее.

1 Ответ

1 голос
/ 25 апреля 2011

Это легко решается с помощью двух регулярных выражений.Первое регулярное выражение, примененное ко всему тексту, соответствует каждому списку в скобках значений, разделенных запятыми.Второе регулярное выражение, примененное к каждому из ранее сопоставленных списков, соответствует каждому значению в списке.Вот 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() вызывает функцию PHP preg_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_].Это можно легко изменить, если это не соответствует вашим требованиям.

Редактировать: Вот версия Javascript функции substitute_random_value():

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)];
        });
}
...