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

时间:2013-06-06 21:02:24

标签: php mysql 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 =蓝色。我已经获得了知道如何解析这些字符串并正确传递信息的PHP代码,但有一个例外:由于可能过于复杂的原因无法进入此处,选项的顺序需要是3,4,2,5,6。 (尝试修改系统的其余部分以接受当前的顺序将是一项过于具有纪念意义的任务。)如果特定组合没有所有五个选项,那就没问题了,例如“{3} 7 {2} 44”交付预期的结果。问题在于包含选项2和选项4的组合 - 需要切换它们的顺序,以便包含选项2和4的任何组合,{4}及其相应的值在{2}之前并且它对应值。

我已经尝试将列添加到Excel并使用Text to Columns,将它们按“{”和“}”字符拆分并重新排序列,但由于并非每个字符串都产生相同数量的列,订单以其他方式搞砸了(比如选项2在选项2之前出现)。

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

TL; DR:我有一堆像上面引用的字符串。在包含“{2}”和“{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中尝试了所有这些解决方案,并且所有这些解决方案都有效),我会,但我的代表太低了。

3 个答案:

答案 0 :(得分:1)

这样的事情对你有用吗?前9行只是将您的字符串转换为数组,每个元素都是选项号和值的数组。订单建立订单以显示项目,最后一个订单使用订单数组进行仓位。

$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数组的正确位置。

答案 1 :(得分:0)

首先,这些选项可能应该在一个单独的表中。你正在破坏各种规范化规则,将这些东西塞进一个像这样的字符串中。

但是如果你真的想在php中解析它,请将字符串拆分为key =&gt; 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);

答案 2 :(得分:0)

这是一个简洁的解决方案:

$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);