对于某些数据处理,我需要将字符串拆分为多个项目。 输入字符串的示例是:
'one, two & three and four-five 123-456'
现在,我需要将此字符串分成项目,其中可能的分隔符是
,
、&
、
(空格)、and
、-
。但是,这就是我陷入困境的地方,当它位于两个数字之间时,它不应该在 -
上分割。
我正在使用 PHP 和
preg_split
进行实际的拆分,但我需要一个正则表达式模式来匹配分隔符,排除两个数字之间的分隔符 -
(数字,但也可以是 123-456
)。在 PHP 中使用 trim()
可以抑制每个项目周围的空格。
我正在使用以下正则表达式模式:
/(and|,|\s|&)|\D(-)\D/
输出(使用
preg_split
等后)是:
[0] => one
[1] => two
[2] => three
[3] => fou
[4] => ive
[5] => 123-456
工作是正确的,但它也采用周围文本的最后一个和第一个字母作为
-
分隔符。项目 123-456
是正确的,因为当它立即被数字包围时,它不应该在 preg_split
上匹配(并与 -
分开)。
预期输出是:
[0] => one
[1] => two
[2] => three
[3] => four
[4] => five
[5] => 123-456
感谢任何帮助,如果缺少任何信息,请告诉我,我会更新我的问题。
您要使用的是lookahead和lookbehind(通常称为lookaround):
/and|,|\s|&|(?<!\d)-(?!\d)/
这将执行的操作正是顾名思义 - 环顾四周以检查指定的模式是否匹配,不匹配它。在这种情况下,它只会匹配两边没有被数字字符(
-
)包围的\d
,但匹配只会是-
本身。
在这种情况下,
(?<!\d)
是一个负向后查找 - 它将向后查看紧邻的前一个字符串是否不与模式匹配。如果匹配,则会报告匹配失败并继续。同样,(?!\d)
是一个负前瞻——它的作用完全相同,但方向相反。因为 -
夹在它们之间,所以效果是“如果 -
两边都没有数字字符,则只匹配它”。
保护数字包围的连字符的另一种方法是利用
(*SKIP)(*FAIL)
——基本上你匹配并丢弃应该被取消资格的子字符串。 Sebastian 答案中的环视模式需要 10 个步骤来解析字符串。
以下模式将需要 7 个步骤来解析字符串。我将单个定界字符和空白序列合并到一个字符类中,并添加了一个或多个量词来提高性能并减少爆炸次数。
代码:(演示)
$string = 'one, two & three and four-five 123-456';
var_export(
preg_split('/\d-\d(*SKIP)(*FAIL)|and|[\s,&-]+/i', $string, 0, PREG_SPLIT_NO_EMPTY)
);
输出:
array (
0 => 'one',
1 => 'two',
2 => 'three',
3 => 'four',
4 => 'five',
5 => '123-456',
)
公平地说,
/and|[\s,&]+|(?<!\d)-(?!\d)/i
还将分 7 个步骤解析输入字符串,因此这取决于模式简洁性或个人喜好。 (演示)
var_export(
preg_split('/and|[\s,&]+|(?<!\d)-(?!\d)/i', $string, 0, PREG_SPLIT_NO_EMPTY)
);