重新排序字符串';使用php regexp调用s行

重新排序字符串';使用php regexp调用s行,php,regex,algorithm,Php,Regex,Algorithm,我需要使用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 = " so

我需要使用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;
但它确实改变了exta:

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*,
然后移除*


还有更优雅的解决方案吗?

更复杂,但算法可能是这样的:

  • 替换行以具有唯一占位符的
    “{Variant#”
    开头,即
    “%line”。$i
    其中
    $i
    是自动递增的,并将删除的部分存储在临时数组中。这可以通过
    preg\u Replace\u callback()
    方法完成
  • 排序临时数组
  • 通过
    preg\u Replace\u callback()
    再次使用临时数组中的连续项替换占位符

  • 为什么不构建一个算法来实际执行您想要执行的操作,即对
    {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);
    

    出于某种原因,上面的代码在PHP7中不起作用

    $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);
    
    这是通过首先用“变体”编号标记每一行(如果有)来实现的。然后,它将列表向下过滤到只有这些行并对它们进行排序。最后,它再次在所有行上循环,要么保持原样(如果不是变体),要么用下一个排序的变体行替换


    >演示

    对于手动交换,您需要交换两对以获得所需的顺序。我注意到这段代码在PHP5中工作,而不是PHP7。我不确定原因。我只能假设
    usort
    实现已更改,导致它与此算法不配合。如果这是一个问题,请告诉我,我会看到如果我能重新处理它,使其在PHP7中工作。不过,我第一次遇到了回归!是的,我考虑过这种方法,但我希望找到更“干净”的解决方案。。。