我需要使用php regexp重新排序字符串中的行。但是我不知道如何告诉PHP不要两次更改同一行。让我解释一下。
输入字符串为:
$comment = "
some text
{Varinat #3 smth}
{Varinat #4 smth else}
{Varinat #1 smth else 1}
some another text
{Varinat #2 smth else 2}
{Varinat #5 smth else 5}
";
我需要订购变体:
$comment = "
some text
{Varinat #1 smth else 1}
{Varinat #2 smth else 2}
{Varinat #3 smth}
some another text
{Varinat #4 smth else}
{Varinat #5 smth else 5}
";
我有代码:
$variants = [
3 => 1,
4 => 2,
1 => 3,
2 => 4,
5 => 5,
];
$replacements = [];
foreach ($variants as $key => $variant) {
$replacements['/{Varinat #'.$variant.'\ /is'] = '{Varinat #'.$key . ' ';
}
$comment = preg_replace(array_keys($replacements), array_values($replacements), $comment);
echo $comment;
但是它确实改变了:
some text
{Varinat #1 smth}
{Varinat #2 smth else}
{Varinat #1 smth else 1}
some another text
{Varinat #2 smth else 2}
{Varinat #5 smth else 5}
如您所见,第1和2行加倍。 发生这种情况是因为php确实发生了变化:3-> 1,然后1-> 3。
我唯一的解决方法是:将行更改为
3 => 1*,
4 => 2*,
1 => 3*,
2 => 4*,
5 => 5*,
然后删除*
还有更优雅的解决方案吗?
答案 0 :(得分:3)
为什么不构建一种算法来实际执行您想做的事情,那就是对{Varinat
行进行排序?
$lines = explode("\n",$comment); // assuming $comment is your input here
$numbered_lines = array_map(null,$lines,range(1,count($lines)));
usort($numbered_lines,function($a,$b) {
if( preg_match('(^\{Varinat #(\d+))', $a[0], $match_a)
&& preg_match('(^\{Varinat #(\d+))', $b[0], $match_b)) {
return $match_a[1] - $match_b[1]; // sort based on variant number
}
return $a[1] - $b[1]; // sort based on line number
});
$sorted_lines = array_column($numbered_lines,0);
$result = implode("\n",$sorted_lines);
由于某些原因,以上代码在PHP 7中不起作用。这是一个替代方法。
$lines = explode("\n",$comment);
$processed = array_map(function($line) {
if( preg_match('(^\{Varinat #(\d+))', $line, $match)) {
return [$line,$match[1]];
}
return [$line,null];
}, $lines);
$variant = array_filter($processed,function($data) {return $data[1];});
usort($variant,function($a,$b) {return $a[1] - $b[1];});
$sorted = array_map(function($data) use (&$variant) {
if( $data[1]) return array_shift($variant)[0];
else return $data[0];
},$processed);
$result = implode("\n",$sorted);
这可以通过首先用“变体”数字标记每行(如果有)来实现。然后,它将列表筛选为仅这些行并对其进行排序。最后,它再次遍历所有行,或者保持原样(如果不是变体),或者将其替换为下一个排序的变体行。
> 3v4l上的演示
答案 1 :(得分:0)
更复杂,但是算法看起来像这样:
"{Variant #"
开头,即"%line" . $i
,其中$i
是自动递增的,并将删除的部分存储在临时数组中。可以通过preg_replace_callback()
方法完成preg_replace_callback()
再次替换临时数组中具有连续项的占位符。