如何在较大的字符串中更改子字符串的顺序


How to change order of substrings inside a larger string?

这相当令人困惑,但我会尽我所能解释…

我有一个MYSQL表充满这样的字符串:

{3}12{2}3{5}52    
{3}7{2}44    
{3}15{2}2{4}132{5}52{6}22
{3}15{2}3{4}168{5}52

每个字符串是产品选项和选项值的组合。{}中的数字是选项,例如{3}= Color。紧跟在每个{}数字后面的数字是该选项的值,例如12 = Blue。我已经有了知道如何解析这些字符串并正确传递信息的PHP代码,但有一个例外:由于可能过于复杂的原因,选项的顺序需要为3,4,2,5,6。(试图修改系统的其余部分以接受当前的秩序将是一项艰巨的任务。)如果一个特定的组合没有全部五个选项也没关系,例如"{3}7{2}44"提供了预期的结果。问题在于包含选项2和选项4的组合——它们的顺序需要改变,以便任何包含选项2和4的组合,{4}及其对应的值都在{2}及其对应的值之前。

我已经尝试将列带入Excel并使用文本到列,通过"{"answers"}"字符将它们分开并重新排序列,但由于不是每个字符串产生相同数量的列,顺序在其他方面变得混乱(如选项5出现在选项2之前)。

我还尝试过使用PHP将每个字符串分解成一个数组(我认为我可以重新排序),使用"}"作为分隔符,但我也没有运气,因为数字以其他方式混合在一起,使它们无法使用。

TL;DR:我有一堆像上面引用的字符串。在每个同时包含"{2}"answers"{4}"的字符串中,需要交换这两个值的位置,以便{4}和它后面的数字位于{2}和它后面的数字之前。换句话说:

{3}15{2}3{4}168{5}52 

需要变成

{3}15{4}168{2}3{5}52
在伪代码中,我能找到的最接近的解决方案是:
for each string,
  if "{4}" is present in this string AND "{2}" is present in this string,
     take the "{4}" and every digit that follows it UNTIL you hit another "{" and store that substring as a variable, then remove it from the string.
     then, insert that substring back into the string, at a position starting immediately before the "{2}".

我希望这是有意义的…

是否有任何方式与PHP, Excel, notepad++,正则表达式等,我可以做到这一点?如有任何帮助,我将不胜感激。

编辑补充:在几个人发布了解决方案之后,我尝试了,我意识到提到我的主机运行PHP 5.2.17是至关重要的,这似乎不允许我们使用自定义排序进行排序。如果我能给每个人的解决方案投票(我在PHP Sandbox中尝试过的所有解决方案都有效),我会的,但我的代表太低了。

这样的东西如何为您工作?前9行只是将字符串转换为数组,每个元素都是选项number和value的数组。Order为要出现的项目建立一个顺序,最后使用顺序数组对位置进行排序。

$str = "{3}15{2}2{4}132{5}52{6}22";
$matches = array();
preg_match_all('/'{([0-9]+)'}([0-9]+)/', $str, $matches);
array_shift($matches);
$options = array();
for($x = 0; $x < count($matches[0]); $x++){
    $options[] = array($matches[0][$x], $matches[1][$x]);
}
$order = [3,4,2,5,6];
usort($options, function($a, $b) use ($order) {
   return array_search($a[0], $order) - array_search($b[0], $order); 
});

要将数据恢复到所需的格式,只需

$str = "";
foreach($options as $opt){
    $str.="{".$opt[0]."}".$opt[1];
}

这里的一个好处是,当你添加一个新的选项类型插入调整顺序只是插入选项号在$order数组的正确位置的问题。

首先,这些选项应该放在一个单独的表中。你违反了所有的规范化规则,把这些东西塞进这样的字符串。

但如果你真的想在php中解析它,将字符串分割成一个key=>value数组,像这样:

$options = [];
$pairs = explode('{', $option_string);
foreach($pairs as $pair) {
    list($key,$value) = explode('}', $pair);
    $options[$key] = $value;
}

我想这会给你:

$options[3]=15;
$options[2]=3;
$options[4]=168;
$options[5]=52;

另一个选择是使用某种现有的序列化(php中的serialize()或json_encode()),而不是滚动您自己的:

$options_string = json_encode($options);
// store $options_string in db
然后

// get $options_string from db
$options = json_decode($options_string);

这里有一个简洁的解决方案:

$order  = array(3, 4, 2, 5, 6);
$string = '{3}15{2}3{4}168{5}52';
$split  = preg_split('#'b(?={)#', $string);

usort($split, function($a, $b) use ($order) {
    $a = array_search(preg_replace('#^{('d+)}'d+$#', '$1', $a), $order);
    $b = array_search(preg_replace('#^{('d+)}'d+$#', '$1', $b), $order);
    return $a - $b;
});
$split = implode('', $split);

var_dump($split);