1

这相当令人困惑,但我会尽力解释......

我有一个 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} = 颜色。每个 { } 数字后面的数字是该选项的值,例如 12 = 蓝色。我已经有了知道如何解析这些字符串并正确传递信息的 PHP 代码,但有一个例外:由于可能过于复杂而无法进入这里的原因,选项的顺序需要为 3,4,2,5,6。(尝试修改系统的其余部分以接受当前订单将是一项艰巨的任务。)如果特定组合没有全部五个选项,那很好,例如“{3}7{2}44”交付预期的结果。问题仅在于包含选项 2 和选项 4 的组合——它们的顺序需要切换,以便任何同时包含选项 2 和 4、{4} 及其对应值的组合出现在 {2} 之前并且它是对应的价值。

我尝试将该列引入 Excel 并使用 Text to Columns,将它们按“{”和“}”字符拆分并重新排序列,但由于并非每个字符串都产生相同数量的列,因此顺序得到以其他方式搞砸了(比如选项 5 出现在选项 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 中尝试过的所有解决方案都有效),我会的,但我的代表太低了。

4

3 回答 3

1

这样的事情对你有什么用。前 9 行只是将您的字符串转换为一个数组,每个元素都是一个包含选项编号和值的数组。Order 为要出现的项目建立一个顺序,最后一个使用 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 数组的正确位置即可。

于 2013-06-06T21:17:42.550 回答
0

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

但如果你真的想在 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);
于 2013-06-06T21:14:29.370 回答
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);
于 2013-06-06T21:50:32.860 回答