PHP regex从给定字符串匹配键值对


PHP regex to match key value pairs from a given string

希望有人能帮忙。

我有一个如下的字符串

$string = 'latitude=46.6781471,longitude=13.9709534,options=[units=auto,lang=de,exclude=[hourly,minutely]]';

现在我要尝试的是创建一个数组的每个键,值对,但严重失败与preg_match_all() regex

目前我的尝试并没有给出预期的结果,只要没有括号,创建键=>值对就可以工作,但我绝对不知道如何实现多维数组,如果键在括号内包含键/值对。

Array (
[0] => Array
    (
        [0] => latitude=46.6781471,
        [1] => longitude=13.9709534,
        [2] => options=[units=si,
        [3] => lang=de,
    )
[1] => Array
    (
        [0] => latitude
        [1] => longitude
        [2] => options=[units
        [3] => lang
    )
.. and so on

最后我想达到的结果如下。

Array (
[latitude] => 46.6781471
[longitude] => 13.9709534
[options] => Array
    (
        [units] => auto
        [exclude] => hourly,minutely
    )
)

我很感激任何帮助或例子,我如何能从一个给定的字符串实现这一点。

正则表达式不是处理递归匹配的正确工具。您可以编写解析器而不是正则表达式(或使用JSON,查询字符串,XML或任何其他常用格式):

function parseOptionsString($string) {
    $length        = strlen($string);
    $key           = null;
    $contextStack  = array();
    $options       = array();
    $specialTokens = array('[', ']', '=', ',');
    $buffer     = '';
    $currentOptions = $options;
    for ($i = 0; $i < $length; $i++) {
        $currentChar = $string[$i];
        if (!in_array($currentChar, $specialTokens)) {
            $buffer .= $currentChar;
            continue;
        }
        if ($currentChar == '[') {
            array_push($contextStack, [$key, $currentOptions]);
            $currentOptions[$key] = array();
            $currentOptions       = $currentOptions[$key];
            $key                  = '';
            $buffer               = '';
            continue;
        }
        if ($currentChar == ']') {
            if (!empty($buffer)) {
                if (!empty($key)) {
                    $currentOptions[$key] = $buffer;    
                } else {
                    $currentOptions[] = $buffer;
                }
            }

            $contextInfo     = array_pop($contextStack);
            $previousContext = $contextInfo[1];
            $thisKey         = $contextInfo[0];
            $previousContext[$thisKey] = $currentOptions;
            $currentOptions        = $previousContext;
            $buffer                = '';
            $key                   = '';
            continue;
        }
        if ($currentChar == '=') {
            $key    = $buffer;
            $buffer = '';
            continue;
        }
        if ($currentChar == ',') {
            if (!empty($key)) {
                $currentOptions[$key] = $buffer; 
            } else if (!empty($buffer)) {
                $currentOptions[] = $buffer;
            }
            $buffer        = '';
            $key           = '';
            continue;
        }
    }
    if (!empty($key)) {
        $currentOptions[$key] = $buffer;
    }
    return $currentOptions;
} 

输出如下:

print_r(parseOptionsString($string));
Array
(
    [latitude] => 46.6781471
    [longitude] => 13.9709534
    [options] => Array
        (
            [units] => auto
            [lang] => de
            [exclude] => Array
                (
                    [0] => hourly
                    [1] => minutely
                )
        )
)

还要注意,对于只有逗号分隔值的数组,您需要一种特殊的语法(exclude=[hour, minuminute]变成exclude=> hour, minuminute,而not exclude=> array(hour, minuminute))。我认为这是你的格式不一致,我写的解析器与"正确"的版本。

如果您不需要解析器,您也可以尝试这段代码。它将字符串转换为JSON并解码为数组。但正如其他人所说,我认为您应该尝试使用JSON的方法。如果你在JavaScript中通过XmlHttpRequest发送这个字符串,那么创建合适的JSON代码来发送并不难。

$string = 'latitude=46.6781471,longitude=13.9709534,options=[units=auto,lang=de,exclude=[hourly,minutely]]';
$string = preg_replace('/([^=,'[']'s]+)/', '"$1"', $string);
$string = '{' . $string . '}';
$string = str_replace('=', ':', $string);
$string = str_replace('[', '{', $string);
$string = str_replace(']', '}', $string);
$string = preg_replace('/({[^:}]*})/', '|$1|', $string);
$string = str_replace('|{', '[', $string);
$string = str_replace('}|', ']', $string);
$result = json_decode($string, true);
print_r($result);