在“and”和一些符号上拆分字符串,但如果被数字包围,则防止在连字符上拆分

问题描述 投票:0回答:2

对于某些数据处理,我需要将字符串拆分为多个项目。 输入字符串的示例是:

'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

感谢任何帮助,如果缺少任何信息,请告诉我,我会更新我的问题。

php regex regex-lookarounds preg-split delimited
2个回答
3
投票

您要使用的是lookahead和lookbehind(通常称为lookaround):

/and|,|\s|&|(?<!\d)-(?!\d)/

这将执行的操作正是顾名思义 - 环顾四周以检查指定的模式是否匹配,不匹配它。在这种情况下,它只会匹配两边没有被数字字符(

-
)包围的
\d
,但匹配只会是
-
本身。

在这种情况下,

(?<!\d)
是一个负向后查找 - 它将向后查看紧邻的前一个字符串是否不与模式匹配。如果匹配,则会报告匹配失败并继续。同样,
(?!\d)
是一个负前瞻——它的作用完全相同,但方向相反。因为
-
夹在它们之间,所以效果是“如果
-
两边都没有数字字符,则只匹配它”。


0
投票

保护数字包围的连字符的另一种方法是利用

(*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)
);
© www.soinside.com 2019 - 2024. All rights reserved.