From a multiline input I want to move tokens if they're inside {} and match some number. Sample input
# (811) (1485) [2756] {29} [555] {15}
# (811) (1476) {20} {15} (1485) [196] [2441]
# (911) (619) {19} (1476) [2765] [2752] {21}
From the above line, I want to move tokens if it's not {19} or {20} to the end of line.
Sample output
# (811) (1485) [2756] [555] {15} {29}
# (811) (1476) {20} (1485) [196] [2441] {15}
# (911) (619) {19} (1476) [2765] [2752] {21}
I can do a preg match with preg_match_all("/\{\d+\}/", $input, $matches);
but then what to do?
You can gather all the matches for {19}
and {20}
per line in an array while filtering the splitted string, and then joining them back together.
Code example
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;
}
Output
# (811) (1485) [2756] [555] {15} {29}
# (811) (1476) {20} (1485) [196] [2441] {15}
# (911) (619) {19} (1476) [2765] [2752] {21}
About the code
Te code first splits the string on newlines, because the moving parts are per line.
Then you can use for example explode to split the line on a space and use array_reduce to inspect the separate parts.
You can initialise array reduce with an array that contains 2 arrays ['valid' => [], 'move' => []]
In the callback function, the accumulator $acc
then already contains that array, which you can then populate with the difference in matches by using the array key like $acc['valid']
The pattern {(?!19|20)\d+}
matches {
and then asserts that it is not directly followed by either 19}
or 20}
If that is the case, it matches 1 or more digits between curly braces.
To get a result with just single spaces between the "words" you can merge both arrays, and then use implode on a space.
See a php demo.