使用正则表达式提取数据(匹配前带有可选字符串)
Extract data with regex (with optional string before the match)
我有一个字符串数组。我正在尝试从每个字符串中提取括号 ( 和 ) 中的数据。问题是它不会从第一个元素中提取中间的数据,如果它前面没有其他内容。
这是指示 needed/captured 值的代码片段:
<?php
$data = [
'aaa|45.85[u]52.22 - 43.75 - 36.5[d]25.75',
// #1^^^ #2^^^^^ #3^^^^^ #4^^^^^
'bbb|238.4[u]345.45 - 24.1[d]13.85 - 56.4[d]56'
// #1^^^ #2^^^^^^ #3^^^^^ #4^^
];
$new = [];
foreach ($data as $element)
{
preg_match("#^(.*?)\|[\w\[\.]+\]?(.*?) - [\w\[\.]+\]?(.*?) - [\w\[\.]+\]?(.*?)$#", $element, $match);
$string = $match[1];
$num1 = $match[2];
$num2 = $match[3];
$num3 = $match[4];
$new[$string] = [
'num1' => $num1,
'num2' => $num2,
'num3' => $num3,
];
}
print_r($new);
?>
上面的代码应该给我这样的结果:
$new = [
'aaa' => [
'num1' => '52.22',
'num2' => '43.75',
'num3' => '25.75',
],
'bbb' => [
'num1' => '345.45',
'num2' => '13.85',
'num3' => '56',
]
];
但它给了我这个:
$new = [
'aaa' => [
'num1' => '52.22',
'num2' => '',
'num3' => '25.75',
],
'bbb' => [
'num1' => '345.45',
'num2' => '13.85',
'num3' => '56',
]
];
查看此演示,了解您的第二个 [\w\[\.]+
字符 class 是如何 over-matching 因为点和数字是贪婪匹配的,并且您的捕获组允许 zero-width 匹配。 https://regex101.com/r/zq6czS/1
只有两个示例字符串,很难自信地提出真正优化的模式,但我建议寻找贪婪量词的方法以提高性能。
- 在第一个竖线之前,收集所有不是竖线的字符 --
([^|]+)
.
- 要在可选出现的“float then square-braced letter”之后捕获 non-whitespace 子字符串,再次使用否定字符 class --
(?:[^\]]+\])?(\S+)
#2 中的建议只重复了三遍;当然,由“space连字符 space”分隔。
代码:(Demo) (or with functionless assignments)
$data = [
'aaa|45.85[u]52.22 - 43.75 - 36.5[d]25.75',
'bbb|238.4[u]345.45 - 24.1[d]13.85 - 56.4[d]56'
];
$result = [];
foreach ($data as $element) {
if (preg_match("#^([^|]+)\|(?:[^\]]+\])?(\S+) - (?:[^\]]+\])?(\S+) - (?:[^\]]+\])?(\S+)$#", $element, $matches)) {
unset($matches[0]);
$result[array_shift($matches)] = array_combine(['num1', 'num2', 'num3'], $matches);
}
}
var_export($result);
一旦你有了你的 5 元素输出匹配数组,删除全字符串匹配 ($matches[0]
),然后剥离新的第一个元素并将其用作第一级键,然后剩余的元素可以是添加到子数组。
我有一个字符串数组。我正在尝试从每个字符串中提取括号 ( 和 ) 中的数据。问题是它不会从第一个元素中提取中间的数据,如果它前面没有其他内容。
这是指示 needed/captured 值的代码片段:
<?php
$data = [
'aaa|45.85[u]52.22 - 43.75 - 36.5[d]25.75',
// #1^^^ #2^^^^^ #3^^^^^ #4^^^^^
'bbb|238.4[u]345.45 - 24.1[d]13.85 - 56.4[d]56'
// #1^^^ #2^^^^^^ #3^^^^^ #4^^
];
$new = [];
foreach ($data as $element)
{
preg_match("#^(.*?)\|[\w\[\.]+\]?(.*?) - [\w\[\.]+\]?(.*?) - [\w\[\.]+\]?(.*?)$#", $element, $match);
$string = $match[1];
$num1 = $match[2];
$num2 = $match[3];
$num3 = $match[4];
$new[$string] = [
'num1' => $num1,
'num2' => $num2,
'num3' => $num3,
];
}
print_r($new);
?>
上面的代码应该给我这样的结果:
$new = [
'aaa' => [
'num1' => '52.22',
'num2' => '43.75',
'num3' => '25.75',
],
'bbb' => [
'num1' => '345.45',
'num2' => '13.85',
'num3' => '56',
]
];
但它给了我这个:
$new = [
'aaa' => [
'num1' => '52.22',
'num2' => '',
'num3' => '25.75',
],
'bbb' => [
'num1' => '345.45',
'num2' => '13.85',
'num3' => '56',
]
];
查看此演示,了解您的第二个 [\w\[\.]+
字符 class 是如何 over-matching 因为点和数字是贪婪匹配的,并且您的捕获组允许 zero-width 匹配。 https://regex101.com/r/zq6czS/1
只有两个示例字符串,很难自信地提出真正优化的模式,但我建议寻找贪婪量词的方法以提高性能。
- 在第一个竖线之前,收集所有不是竖线的字符 --
([^|]+)
. - 要在可选出现的“float then square-braced letter”之后捕获 non-whitespace 子字符串,再次使用否定字符 class --
(?:[^\]]+\])?(\S+)
#2 中的建议只重复了三遍;当然,由“space连字符 space”分隔。
代码:(Demo) (or with functionless assignments)
$data = [
'aaa|45.85[u]52.22 - 43.75 - 36.5[d]25.75',
'bbb|238.4[u]345.45 - 24.1[d]13.85 - 56.4[d]56'
];
$result = [];
foreach ($data as $element) {
if (preg_match("#^([^|]+)\|(?:[^\]]+\])?(\S+) - (?:[^\]]+\])?(\S+) - (?:[^\]]+\])?(\S+)$#", $element, $matches)) {
unset($matches[0]);
$result[array_shift($matches)] = array_combine(['num1', 'num2', 'num3'], $matches);
}
}
var_export($result);
一旦你有了你的 5 元素输出匹配数组,删除全字符串匹配 ($matches[0]
),然后剥离新的第一个元素并将其用作第一级键,然后剩余的元素可以是添加到子数组。