Из многострочного ввода я хочу переместить токены, если они находятся внутри {} и соответствуют некоторому числу. Пример ввода
# (811) (1485) [2756] {29} [555] {15}
# (811) (1476) {20} {15} (1485) [196] [2441]
# (911) (619) {19} (1476) [2765] [2752] {21}
Из приведенной выше строки я хочу переместить токены, если это не {19} или {20}, в конец строки.
Пример вывода
# (811) (1485) [2756] [555] {15} {29}
# (811) (1476) {20} (1485) [196] [2441] {15}
# (911) (619) {19} (1476) [2765] [2752] {21}
Я могу провести предварительный матч с preg_match_all("/\{\d+\}/", $input, $matches);, но что тогда делать?






Вы можете собрать все совпадения для {19} и {20} для каждой строки в массиве, отфильтровав разделенную строку, а затем снова соединив их вместе.
Пример кода
foreach (explode("\n", $str) as $str) {
$result = array_reduce(explode(" ", $str), function($acc, $curr) {
preg_match("/{(?!19|20)\d+}/", $curr) ? $acc['move'][] = $curr : $acc['valid'][] = $curr;
return $acc;
}, ['valid' => [], 'move' => []]);
echo implode(" ", array_merge($result['valid'], array_reverse($result['move']))) . PHP_EOL;
}
Выход
# (811) (1485) [2756] [555] {15} {29}
# (811) (1476) {20} (1485) [196] [2441] {15}
# (911) (619) {19} (1476) [2765] [2752] {21}
О коде
Код сначала разбивает строку на символы новой строки, потому что движущиеся части находятся в каждой строке.
Затем вы можете использовать, например, разнесение, чтобы разделить строку на пробел, и использовать array_reduce для проверки отдельных частей.
Вы можете инициализировать уменьшение массива с помощью массива, содержащего 2 массива ['valid' => [], 'move' => []]
В функции обратного вызова аккумулятор $acc уже содержит этот массив, который вы затем можете заполнить разницей в совпадениях, используя ключ массива, например $acc['valid']
Шаблон {(?!19|20)\d+} соответствует {, а затем утверждает, что за ним непосредственно не следует ни 19}, ни 20}. Если это так, то он соответствует 1 или более цифрам между фигурными скобками.
Чтобы получить результат с одним пробелом между «словами», вы можете объединить оба массива, а затем использовать implode для пробела.
См. демонстрация php.
@www.friend0.in Я добавил объяснение кода.
Это решение позволяет использовать несколько знаков препинания. В этом примере все токены, начинающиеся с '{' или '(', будут перемещены в конец:
$input = <<< STRING
# (811) (1485) [2756] {29} [555] {15}
# (811) (1476) {20} {15} (1485) [196] [2441]
# (911) (619) {19} (1476) [2765] [2752] {21}
STRING;
$excluded = [ '{19}', '{20}', '(811)' ];
$startPunctuations = array_unique(array_map(fn($exclude) => $exclude[0], $excluded));
$result = implode(
"\n",
array_map(
fn($line): string => implode(
' ',
array_map(
fn($element) => implode(' ', $element),
array_reduce(
explode(' ', $line),
fn($carry, $item) => in_array($item[0], $startPunctuations) && !in_array($item, $excluded)
? [ $carry[0], [ ...$carry[1], $item ] ]
: [ [ ...$carry[0], $item ], $carry[1] ],
[ [], [] ]
)
)
),
explode("\n", $input)
)
);
echo $result;
// # (811) [2756] [555] (1485) {29} {15}
// # (811) {20} [196] [2441] (1476) {15} (1485)
// # {19} [2765] [2752] (911) (619) (1476) {21}
Пожалуйста объясните код