2013-06-06 2 views
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}". 

I надеюсь, что это какой-то смысл ...

Есть любой путь с PHP, Excel, Notepad ++, регулярные выражения и т. Д., Что я могу это сделать? Любая помощь будет безумно оценена.

EDITED TO ADD: После нескольких опубликованных нами решений, которые я пробовал, я понял, что было бы важно отметить, что мой хост работает с PHP 5.2.17, который, похоже, не позволяет использовать usort с пользовательской сортировкой. Если бы я мог решить все решения (все, что я пробовал в PHP Sandbox, и все это сработало), я бы сделал, но мой представитель слишком низок.

+0

Я думаю, что 'awk' является правильным инструментом для такого рода проблемы, но теперь я из практики, чтобы дать вам готовый ответ. – naitoon

ответ

0

Прежде всего, эти параметры, вероятно, должны быть в отдельной таблице. Вы нарушаете все правила нормализации, набирая эти вещи в такую ​​строку.

Но если вы действительно хотите, чтобы разобрать, что в PHP, разделить строку в ключевой массив => значение с чем-то вроде этого:

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

Другим вариантом было бы использовать какой-то существующей сериализации (или сериализации() или json_encode() в PHP) вместо того, чтобы добавить собственные:

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

затем

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

Несмотря на то, что все предоставленные решения отлично работали в PHP Sandbox, к сожалению, я не понял, что было бы важно отметить, что мой хост работает с PHP 5.2.17, который, как я только что открыл, запрещает оба решения, которые используют usort и пользовательский объявленный $ order. Хотелось бы, чтобы я мог решить все решения, но мой представитель недостаточно высок. Поэтому я выбираю этот, поскольку я мог использовать цикл foreach здесь, в сочетании с некоторыми неуклюжими, но эффективными операциями if, для создания таблицы с строками опций в правильном порядке. Спасибо всем, кто предложил решения! – geoff

1

Как бы что-то нравится эта работа для вас. Первые 9 строк просто преобразуют вашу строку в массив, причем каждый элемент является массивом номера и значения параметра. Заказ устанавливает порядок появления элементов, а последний использует usort, используя массив заказов для позиций.

$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

Возможно, вы также можете поместить '+' в первую группу в скобках, чтобы ваш код мог обрабатывать случай, когда есть параметры с кодом более одной цифры. Во всяком случае, очень чистое решение, +1 для этого. – naitoon

+0

@naitoon good catch – Orangepill

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); 
Смежные вопросы