【问题标题】:Split only text on special characters, but not on numbers with decimal points仅拆分特殊字符上的文本,但不拆分带小数点的数字
【发布时间】:2011-09-28 15:44:03
【问题描述】:

我正在考虑 PHP 中的一个特殊的正则表达式问题,但我找不到解决方案。 我尝试将一些文本拆分为术语,以获得简单的单词、数字和网址。

所以我决定拆分每个非字母数字字符 (\w)。

为了处理不同的语言,我将 \w 与其他字母一起使用,例如 Ää éèÈ 等。

例子:

20,000 15.20 This is at Text. Right?!
www.google.com Jean Béraud

到目前为止,我使用以下正则表达式来拆分文本:

[^\w(äÄüÜöÖßèé)]

http://regexr.com?2uq98

这在 80% 的情况下效果很好,但将 20,000 分为 20 和 000 也将 www.google.com 分为 www google com

所以我试图把数字放在一起,但仍然在分数上分开,比如Text. 得到Text

为了匹配 15.20,以下方法有效:(\d+\.\d+),但是如何将否定与其他正则表达式字符串结合起来?以下将不起作用:(\d+\.\d+)|[^\w(äÄüÜöÖßèé)]?
以及:如何处理网址?

【问题讨论】:

  • 分割空间不适合你吗?
  • 不,因为我还需要拆分“文本”。到文本'。拆分和空格将忽略 !?.:,;

标签: php regex


【解决方案1】:

这样的?

$result = preg_split('/\W*\s+/', $string, NULL, PREG_SPLIT_NO_EMPTY);

Demo,结果:

array(10) {
  [0]=>
  string(6) "20,000"
  [1]=>
  string(5) "15.20"
  [2]=>
  string(4) "This"
  [3]=>
  string(2) "is"
  [4]=>
  string(2) "at"
  [5]=>
  string(4) "Text"
  [6]=>
  string(5) "Right"
  [7]=>
  string(14) "www.google.com"
  [8]=>
  string(4) "Jean"
  [9]=>
  string(7) "Béraud"
}

问:为什么在我的示例中\wé 匹配?

A:这是基于使用 PCRE 库的系统的本地,来自PHP Manual

“单词”字符是任何字母或数字或下划线字符,即任何可以成为 Perl“单词”一部分的字符。字母和数字的定义由 PCRE 的字符表控制,并且如果发生特定于语言环境的匹配,可能会有所不同。例如,在“fr”(法语)语言环境中,一些大于 128 的字符代码用于重音字母,这些字符由 \w 匹配。

另外,将正则表达式指定为使用 UTF-8 可能会有所帮助:

$result = preg_split('/\W*\s+/u', $string, NULL, PREG_SPLIT_NO_EMPTY);

确保 $string 采用 UTF-8 编码。由于 UTF-8 是国际性的,因此可能不需要考虑特定的区域设置。试试看吧。

【讨论】:

  • 理论上是这个作品,但不在我的服务器配置上,因为外国字母将被匹配为 \W :-( - 我会再次调查这个......
  • 这听起来像是提供 pcre 库的系统上的语言环境问题。您可能需要使用 mb_string 扩展中的一些正则表达式函数和/或正确检查编码/字符集。
  • 看起来,preg_splitmb_string 世界中不存在。另一方面:您在没有mb_* 命令的情况下使用 preg_split 并得到正确的结果。你是怎么做到的?
  • @TheBndr:我已经为答案添加了解释,可能还有其他解决方法,请尝试。
  • 谢谢 - 我玩过那些 mb_* 的东西,发现 $string 不是 UTF-8 mb_check_encoding($string, 'UTF-8')。所以我通过使用$string = mb_convert_encoding($string, "UTF-8");$string 更改为UTF-8,现在'/\W*\s+/u' 效果很好。 :-) 太感谢了!!现在我尝试将您的 rexexp 更改为在单词的开头或结尾处拆分 ' ,拆分到 'here we go': 'here herego'th go (没有开始结束结束 @ 987654344@)
【解决方案2】:

根据@hakre 的回答和您的示例,我相信您应该以这种方式组合这两个表达式:

$result = preg_split('/[^\wäÄüÜöÖßèé]*\s+[^\wäÄüÜöÖßèé]*/', $string, NULL, PREG_SPLIT_NO_EMPTY);

您的原始表达式成功匹配了适当的字符([^\w(äÄüÜöÖßèé)] 部分)。

@hakre 的表达式补充说,可以有任意数量的这些字符(甚至没有字符),并且后面还应该有一个或多个空格实例(\s+ 部分)。

当你把这两个想法结合起来,你得到[^\wäÄüÜöÖßèé]*\s+[^\wäÄüÜöÖßèé]*,它基本上翻译成

任意数量的不在此字符类中的字符,后跟至少一个空白字符,然后可能后跟任意数量的不在此字符类中的字符

一个或多个空白字符,以及不在此字符类中的任意数量的字符,无论是之前还是之后

作为测试,我使用了这个文本示例(我假设你想匹配法语字符):

20,000 15.20 This is at Text. Right?!
www.google.com Comme son élève, où dois-je aller voir Jean Béraud?

还有这个正则表达式: 已编辑

/[^\wßàâäèéêëîïôöœùûüÿç]*(^|$|\s+)[^\wßàâäèéêëîïôöœùûüÿç]*/i

通过@hakre 使用的同一网站:

http://codepad.viper-7.com/MqztVt

结束编辑

此测试表明,即使单词以特殊字符之一开头或结尾,表达式也会拆分。我在表达式末尾添加了/i 开关以使匹配不区分大小写。

【讨论】:

  • 感谢您的回答! /i是一个非常有用的提示。 >我假设你想匹配法语字符codepad.viper-7.com/sQ3WTX)我注意到Béraud? 末尾没有拆分,以便在没有? 的情况下获得Béraud 另一方面,它适用于Right!? ??
  • 我更正了答案中的表达式(并添加了一个新链接),因此它也可以在字符串的开头和结尾工作(并忽略任何开头或结尾的标点符号)-如果你想匹配多个法语字符,将它们添加到每个字符类中。您可以将一个表达式与您能想到的所有特殊字符一起使用,或者您可以将其用于每种语言。根据您使用它的位置,可能有更好的方法来解析您的字符串 - 例如,如果字符串包含 $20,000,您将获得 20,000,并且不知道它是美元、英镑还是里拉
  • 如果您希望保留货币符号,可以将它们添加到相应的字符类中。
  • 感谢您的更新。我会记住这个解决方案,以备将来使用。特别是如果 `\w' 不起作用。谢谢! +1 对于这个特定问题,@hakre 的解决方案更适合我的需求......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-11-13
  • 2017-05-18
  • 1970-01-01
  • 2021-07-02
  • 1970-01-01
相关资源
最近更新 更多