我需要用正则表达式定界符分割字符串,但需要使用定界符作为数组键。
这是一个示例字符串:
*01the title*35the author*A7other useless infos*AEother useful infos*AEsome delimiters can be there multiple times
定界符是一个星号(*),后跟两个字母数字字符。
我使用以下正则表达式模式:/\*[A-Z0-9]{2}/
这是我的preg_split呼叫:
$attributes = preg_split('/\*[A-Z0-9]{2}/', $line);
这可行,但是我需要每个匹配的定界符作为关联数组中值的键。
我得到的是这样的:
$matches = [
0 => 'the title',
1 => 'the author',
2 => 'other useless infos',
3 => 'other useful infos',
4 => 'some delimiters can be there multiple times'
];
它应该像这样:
$matches = [
'*01' => 'the title',
'*35' => 'the author',
'*A7' => 'other useless infos',
'*AE' => [
'other useful infos',
'some delimiters can be there multiple times',
],
];
有人对如何实现这一目标有任何建议吗?
答案 0 :(得分:1)
使用PREG_SPLIT_DELIM_CAPTURE
函数的preg_split
标志还获取捕获的定界符(请参见documentation)。
所以在您的情况下:
# The -1 is the limit parameter (no limit)
$attributes = preg_split('/(\*[A-Z0-9]{2})/', $line, -1, PREG_SPLIT_DELIM_CAPTURE);
现在,您将0
中的元素$attributes
作为第一个定界符之前的所有内容,然后将捕获的定界符和下一组分隔,从而可以像这样构建$matches
数组(假设您不想保留第一组):
for($i=1; $i<sizeof($attributes)-1; $i+=2){
$matches[$attributes[$i]] = $attributes[$i+1];
}
为了解决定界符多次出现的问题,您可以调整for循环内的行以检查此键是否已经存在,并在这种情况下创建一个数组。
编辑:如有必要,可以使用以下代码创建数组:
for($i=1; $i<sizeof($attributes)-1; $i+=2){
$key = $attributes[$i];
if(array_key_exists($key, $matches)){
if(!is_array($matches[$key]){
$matches[$key] = [$matches[$key]];
}
array_push($matches[$key], $attributes[$i+1]);
} else {
$matches[$attributes[$i]] = $attributes[$i+1];
}
}
当然可以简化下游代码,特别是如果将所有值都放在(可能是单个元素)数组中。
答案 1 :(得分:1)
您可以将键匹配并捕获到组1中,并将所有下一个定界符之前的文本捕获到组2中,其中定界符与捕获的第一个定界符不同。然后,循环检查所有键和值,并使用定界符模式(一次或多次出现)分隔这些值。
正则表达式为
(\*[A-Z0-9]{2})(.*?)(?=(?!\1)\*[A-Z0-9]{2}|$)
请参见regex demo。
详细信息
(\*[A-Z0-9]{2})
-分隔符,第1组:一个*
和两个大写字母或数字(.*?)
-值,组2:除换行符以外的任何0+个字符,并且尽可能少(?=(?!\1)\*[A-Z0-9]{2}|$)
-直到分隔符模式(\*[A-Z0-9]{2}
)不等于第1组((?!\1)
)或字符串结尾($
)中捕获的文本。请参见PHP demo:
$re = '/(\*[A-Z0-9]{2})(.*?)(?=(?!\1)\*[A-Z0-9]{2}|$)/';
$str = '*01the title*35the author*A7other useless infos*AEother useful infos*AEsome delimiters can be there multiple times';
$res = [];
if (preg_match_all($re, $str, $m, PREG_SET_ORDER, 0)) {
foreach ($m as $kvp) {
$tmp = preg_split('~\*[A-Z0-9]+~', $kvp[2]);
if (count($tmp) > 1) {
$res[$kvp[1]] = $tmp;
} else {
$res[$kvp[1]] = $kvp[2];
}
}
print_r($res);
}
输出:
Array
(
[*01] => the title
[*35] => the author
[*A7] => other useless infos
[*AE] => Array
(
[0] => other useful infos
[1] => some delimiters can be there multiple times
)
)
答案 2 :(得分:0)
好的,我回答了关于如何处理多个相同定界符的问题。 感谢@ markus-ankenbrand的开始:
$attributes = preg_split('/(\*[A-Z0-9]{2})/', $line, -1, PREG_SPLIT_DELIM_CAPTURE);
$matches = [];
for ($i = 1; $i < sizeof($attributes) - 1; $i += 2) {
if (isset($matches[$attributes[$i]]) && is_array($matches[$attributes[$i]])) {
$matches[$attributes[$i]][] = $attributes[$i + 1];
} elseif (isset($matches[$attributes[$i]]) && !is_array($matches[$attributes[$i]])) {
$currentValue = $matches[$attributes[$i]];
$matches[$attributes[$i]] = [$currentValue];
$matches[$attributes[$i]][] = $attributes[$i + 1];
} else {
$matches[$attributes[$i]] = $attributes[$i + 1];
}
}
胖的if / else语句看起来不太好,但是可以满足需要。