PHP将分隔的字符串拆分为键/值对(关联数组)

Pyr*_*ite 9 php arrays string associative-array explode

我有一个像这样的字符串:

key1\value1\key2\value2\key3\value3\key4\value4\key5\value5
Run Code Online (Sandbox Code Playgroud)

我希望它是一个关联数组,以便我能做到:

echo $myArray['key1']; // prints value1
echo $myArray['key3']; // prints value3
//etc...
Run Code Online (Sandbox Code Playgroud)

我知道我可以在反斜杠上爆炸,但不知道如何从那里开始.

mar*_*rio 18

使用一个简单的正则表达式通过preg_match_all,并array_combine往往是最短,最快的选项:

 preg_match_all("/([^\\\\]+)\\\\([^\\\\]+)/", $string, $p);
 $array = array_combine($p[1], $p[2]);
Run Code Online (Sandbox Code Playgroud)

现在这当然是一个特例.两个由一个分隔\反斜杠,因为都是对它们.由于必要的双重转义,正则表达式也有点长.

但是,此方案可以推广到其他key:value,样式的字符串.

独特的key:value,分隔符

常见的变体包括:=作为键/值分隔符,和/ ,&作为对分隔符的其他变体.在这种情况下,正则表达式变得相当明显(带有/x可读性标志):

 #                    ?    ?    ?
 preg_match_all("/ ([^:]+) : ([^,]+) /x", $string, $p);
 $array = array_combine($p[1], $p[2]);
Run Code Online (Sandbox Code Playgroud)

这使得交换:,其他分隔符变得非常容易.

  • 等号=而不是:冒号.
  • 例如,\\t作为对分隔符(制表符分隔键:值列表)
  • 经典&;键=值对之间的分隔符.
  • 或者甚至是\\s空格或\\n换行符.

允许不同的分隔符

您可以通过在键/值/对之间允许不同的分隔符来使其更灵活/更宽容:

 #                    ?      ?       ?
 preg_match_all("/ ([^:=]+) [:=]+ ([^,+&]+) /x", $string, $p);
Run Code Online (Sandbox Code Playgroud)

两者key=value,key2:value2++key3==value3都有效.这对于更多人类友好(AKA非技术用户)来说是有意义的.

约束字母数字键

通常,您可能希望禁止除经典key标识符之外的任何内容.只需使用\w+单词字符串模式使正则表达式跳过不必要的出现:

 #                   ?   ?    ?
 preg_match_all("/ (\w+) = ([^,]+) /x", $string, $p);
Run Code Online (Sandbox Code Playgroud)

这是最琐碎的白名单方法.如果OTOH要事先断言 /约束整个键/值字符串,那么就要单独制作preg_match("/^(\w+=[^,]+(,|$))+/", …

剥离空格或引用

您可以通过一些trim小的添加跳过一些后处理步骤(例如在键和值上):

 preg_match_all("/ \s*([^=]+) \s*=\s* ([^,]+) (?<!\s) /x", $string, $p);
Run Code Online (Sandbox Code Playgroud)

或者例如可选引号:

 preg_match_all("/ \s*([^=]+) \s*=\s* '? ([^,]+) (?<![\s']) /x", $string, $p);
Run Code Online (Sandbox Code Playgroud)

INI式提取

您可以制作基线INI文件提取方法:

 preg_match_all("/^ \s*(\w+) \s*=\s* ['\"]?(.+?)['\"]? \s* $/xm", $string, $p);
Run Code Online (Sandbox Code Playgroud)

请注意,这只是普通INI方案的一个粗略子集.

替代方案: parse_str()

如果你已经有一个key=value&key2=value2字符串,那parse_str就像魅力一样.但通过结合它strtr甚至可以处理不同的其他分隔符:

 #                         ??    ??
 parse_str(strtr($string, ":,", "=&"), $pairs);
Run Code Online (Sandbox Code Playgroud)

其中有一些优点和缺点:

  • 甚至比双线正则表达式还要短.
  • 预定义一个众所周知的转义机制,例如%2F特殊字符).
  • 不允许使用不同的分隔符或未转义的分隔符.
  • 自动转换keys[]=为数组,您可能想要也可能不想要.

替代方案:explode+foreach

您将找到许多手动键/值字符串扩展的示例.虽然这通常是更多的代码.explode由于优化假设,在PHP中有点过度使用.然后,由于手动foreach和数组收集,分析经常变慢.


Pas*_*TIN 6

这样的事情怎么样:

$str = 'key1\value1\key2\value2\key3\value3\key4\value4\key5\value5';
$list = explode('\\', $str);

$result = array();
for ($i=0 ; $i<count($list) ; $i+=2) {
    $result[ $list[$i] ] = $list[$i+1];
}

var_dump($result);
Run Code Online (Sandbox Code Playgroud)

哪能得到你:

array
  'key1' => string 'value1' (length=6)
  'key2' => string 'value2' (length=6)
  'key3' => string 'value3' (length=6)
  'key4' => string 'value4' (length=6)
  'key5' => string 'value5' (length=6)
Run Code Online (Sandbox Code Playgroud)


基本上,这里的想法是:

  • 拆分字符串
  • 这会给你一个数组,如 'key1', 'value1', 'key2', 'value2', ...
  • 然后,每次使用2次跳转迭代此列表:
    • 一个元素作为关键 - 指向的元素 $i
    • 就在它之后的一个值 - 指向的那个 $i+1