Разбор строки внутри строки?

У меня есть функция, которая принимает строковый параметр, такой как: "var1 = val1 var2 = val2 var3 = 'список vals'";

Мне нужно разобрать эту строку и выбрать комбинацию var / val. Это достаточно просто до появления чего-то вроде var3 = 'списка vals. Очевидно, я не могу взорвать строку в массив, используя разделитель пробела, который заставляет меня застрять. Я хочу создать массив из этой строки с правильно назначенными парами var / val, как я могу это сделать в случае, когда у меня есть что-то вроде var3?

Related of "Разбор строки внутри строки?"

если формат строки задан в камне, вы можете сделать что-то вроде:

$string = "var1=val1 var2=val2 var3='this is a test'"; $vars = array(); $i = 0; while ($i < strlen($string)) { $eqIndex = strpos($string, "=", $i); $varName = substr($string, $i, $eqIndex - $i); $i = $eqIndex + 1; if ($string[$i] == "'") { $varEndIndex = strpos($string, "'", ++$i); } else { $varEndIndex = strpos($string, " ", $i); if ($varEndIndex === FALSE) $varEndIndex = strlen($string); } $varValue = substr($string, $i, $varEndIndex - $i); $vars[$varName] = $varValue; $i = $varEndIndex + 1; } print_r($vars); 

РЕДАКТИРОВАТЬ:

Более надежная функция, которая обрабатывает экранированные символы в приведенных значениях:

 function getVarNameEnd($string, $offset) { $len = strlen($string); $i = $offset; while ($i < $len) { if ($string[$i] == "=") return $i; $i++; } return $len; } function getValueEnd($string, $offset) { $len = strlen($string); $i = $offset; if ($string[$i] == "'") { $quotedValue = true; $i++; } while ($i < $len) { if ($string[$i] == "\\" && $quotedValue) $i++; else if ($string[$i] == "'" && $quotedValue) return $i + 1; else if ($string[$i] == " " && !$quotedValue) return $i; $i++; } return $len; } function getVars($string) { $i = 0; $len = strlen($string); $vars = array(); while ($i < $len) { $varEndIndex = getVarNameEnd($string, $i); $name = substr($string, $i, $varEndIndex - $i); $i = $varEndIndex + 1; $valEndIndex = getValueEnd($string, $i); $value = substr($string, $i, $valEndIndex - $i); $i = $valEndIndex + 1; $vars[$name] = $value; } return $vars; } $v = getVars("var1=var1 var2='this is a test' var3='this has an escaped \' in it' var4=lastval"); print_r($v); 

Это традиционно, почему строки запроса используют & как разделитель, а не пробелы.

Если вы можете это сделать, просто используйте parse_str для вывода данных.

Если нет, вам нужно сделать регулярное выражение:

 preg_match_all('/(\S*)=('.*?'|\S*)/g', $your_string, $matches); print_r($matches); 

Вы можете использовать регулярное выражение, чтобы найти все соответствующие пары var = val, например

 (\w[0-9A-Za-z]+)=(\'?\w([0-9A-Za-z ]|\\\'|\\=)+\'?) 

то вы можете использовать preg_match_all для их синтаксического анализа, если строка второй группы начинается с символа, который вы можете разобрать.

Не все это задумалось, но как насчет этого? Может быть, LITTLE слишком много кода для такой маленькой задачи 🙂

 <?php function parse_vars($string) { $exploded = explode(" ", $string); $return = array(); foreach($exploded AS $entry){ if(strpos($entry, "=") === false){ $return[$current] .= " ".$entry; }else{ list($key, $value) = explode("=", $entry); $return[$key] = $value; $current = $key; } } return $return; } $string = "var1=val1 var2=val2 var3='a list of vals'"; print_r(parse_vars($string)); die(); ?> 

Кстати, я все еще предпочитаю решение регулярного выражения с помощью "(\S*)=('.*?'|\S*)"

Возможно, вам нужна функция parse_str ()?

Вот пример из PHP.net:

 <?php $str = "first=value&arr[]=foo+bar&arr[]=baz"; parse_str($str); echo $first; // value echo $arr[0]; // foo bar echo $arr[1]; // baz parse_str($str, $output); echo $output['first']; // value echo $output['arr'][0]; // foo bar echo $output['arr'][1]; // baz ?> 

Кажется, он делает именно то, что вы ищете.

Я боюсь, что эта проблема не может быть решена простым регулярным выражением или простым расщеплением. Посмотрите на функцию str_getcsv () в PHP 5.3. Я думаю, вы можете сделать так, как хотите.

 array str_getcsv ( string $input [, string $delimiter [, string $enclosure [, string $escape ]]] ) 

Вы можете указать разделитель как пробел вместо запятой и вложением как одинарную цитату вместо двойной кавычки. Если можно, выкопайте реализацию этой функции, поймите ее и научитесь этому. В противном случае вы сможете использовать PHP 5.3.

Изменить: Там, если у вас нет PHP 5.3:

 if(!function_exists('str_getcsv')) { function str_getcsv($input, $delimiter = ",", $enclosure = '"', $escape = "\\") { $fp = fopen("php://memory", 'r+'); fputs($fp, $input); rewind($fp); $data = fgetcsv($fp, null, $delimiter, $enclosure); // $escape only got added in 5.3.0 fclose($fp); return $data; } } 

Кредит: http://www.electrictoolbox.com/php-str-getcsv-function/

Изменить: Вот реализация в Perl: Text :: CSV . Вы можете скачать источник и посмотреть алгоритмы. Если вы за это 🙂

Использовать RegEx с preg_split() ?

Мне не очень нравится RE, но я уверен, что вы можете использовать это, чтобы предотвратить разделение строки внутри одинарных кавычек.

Ладно, вы не можете его изменить. Я бы использовал такой алгоритм:

1) Замените все строки, содержащиеся внутри кавычек, на уникальный идентификатор и сохраните идентификатор в массиве.

Так

var1 = val1 var2 = val2 var3 = 'список vals'

становится

var1 = val1 var2 = val2 var3 = asifab

array ("asifab" => 'список vals')

2) Разделить пространствами

array ("var1 = val1", "var2 = val2", "var3 = asifab")

array ("asifab" => 'список vals')

3) разделение на равные знаки

array ("var1" => "val1", "var2" => "val2", "var3" => "asifab")

array ("asifab" => 'список vals')

4) Для каждого значения, посмотрите, находится ли он в вашем массиве, и если это так, разделите значение массива по пробелам и используйте это как значение

array ("var1" => "val1", "var2" => "val2", "var3" => array ("a", "list", "of", "values"))