【问题标题】:Regex to match anything (including the empty string) except a specific given string正则表达式匹配除特定给定字符串之外的任何内容(包括空字符串)
【发布时间】:2010-05-14 20:08:25
【问题描述】:

我想测试一个字符串是否包含"Kansas",后跟" State"以外的任何内容。

例子:

"I am from Kansas"          true
"Kansas State is great"     false
"Kansas is a state"         true
"Kansas Kansas State"       true
"Kansas State vs Kansas"    true
"I'm from Kansas State"     false
"KansasState"               true

对于PCRE,我相信答案是这样的:

'Kansas(?! State)'

但是Mysql的REGEXP好像不喜欢这样。

附录:感谢David M 概括了这个问题: How to convert a PCRE to a POSIX RE?

【问题讨论】:

  • 为什么"Kansas Kansas State" 是真的?
  • 因为它包含“Kansas”,后跟“State”以外的其他内容,即“Kansas State”。理由是我想要所有提到“堪萨斯州”的字符串,无论它们是否也提到“堪萨斯州”。例如,“堪萨斯州和堪萨斯州在锦标赛中互相比赛”。那提到堪萨斯州(不仅仅是堪萨斯州),所以我想匹配它。
  • 我添加了更多示例来澄清这一点。
  • 我更新了我的答案。看看我的新正则表达式是否适用于 mysql。
  • poster 指出将简单的 PCRE 转换为完整的 POSIX re 可能很乏味,这引发了一个有趣的问题,即如何自动完成。 stackoverflow.com/questions/2837706/…

标签: sql mysql regex pcre


【解决方案1】:

MySQL 没有前瞻功能。一种解决方法是进行两个测试:

WHERE yourcolumn LIKE '%Kansas%'
  AND yourcolumn NOT LIKE '%Kansas State%'

我在这里使用了LIKE 而不是RLIKE,因为一旦像这样拆分它,就不再需要正则表达式了。但是,如果您出于其他原因仍需要正则表达式,您仍然可以使用相同的技术。

请注意,这与您要求的“Kansas Kansas State”不匹配。

更新:如果匹配 'Kansas Kansas State' 很重要,那么您可以使用 MySQL 支持的这个丑陋的正则表达式:

'Kansas($|[^ ]| ($|[^S])| S($|[^t])| St($|[^a])| Sta($|[^t])| Stat($|[^e]))'

糟糕:我刚刚注意到 Kip 已经用与此非常相似的解决方案更新了他的评论。

【讨论】:

  • 谢谢马克。不过,“堪萨斯堪萨斯州”问题是症结所在。请参阅我添加到有关此问题的评论。
【解决方案2】:

比大型正则表达式(当然取决于您的数据和引擎的质量)更有效

WHERE col LIKE '%Kansas%' AND
  (col NOT LIKE '%Kansas State%' OR
  REPLACE(col, 'Kansas State', '') LIKE '%Kansas%')

如果堪萨斯州通常以“堪萨斯州”的形式出现,您可能会发现这样更好:

WHERE col LIKE '%Kansas%' AND
  REPLACE(col, 'Kansas State', '') LIKE '%Kansas%'

这具有更易于维护的额外优势。如果堪萨斯很常见并且文本字段很大,则效果较差。当然,您可以根据自己的数据进行测试,然后告诉我们它们的比较情况。

【讨论】:

  • 哇,是的,这似乎好多了。 (就我而言,性能不是问题,但这只是更容易输入,更不用说概括了。)谢谢!
【解决方案3】:

这应该可以工作,假设 MySQL 正则表达式中允许使用前瞻断言。

/Kansas(?! State)/

编辑:好的,这非常丑陋,但它在 Perl 中对我有用,并且不使用前瞻断言:

/Kansas(([^ ]|$)| (([^S]|$)|S(([^t]|$)|t(([^a]|$)|a(([^t]|$)|t([^e]|$))))))/

【讨论】:

  • 谢谢基普,当你添加这个答案时,我只是在编辑这个问题!
  • 很好的答案,除了 MySQL 没有实现前瞻断言。
  • 回复:编辑:哇,我印象深刻! :) 不幸的是,MySQL 用“非法变量名”来回应。
  • 值得注意的是,Perl 和 MySQL 有完全不同的正则表达式实现。对于简单的示例,例如我和 Kip 分别实现的示例,它们的性能应该非常相似。但是,不要指望 Perl 和 MySQL 给出相同的答案或相似的性能。
  • 谢谢大家。超级有帮助。似乎 MySQL 应该与该程序一起实现 pcre,嗯?
【解决方案4】:

这很丑,但是你去吧:

您可能不需要将正则表达式一直扩展到最后,这取决于您的输入是否可能包含类似“我需要让这个人在堪萨斯州接受手术!”之类的内容!

mysql> select x,x RLIKE 'Kansas($|[^ ]| ($|[^S])| S($|[^t])| St($|[^a])| Sta($|[^t])| Stat($|[^e]))' AS result from examples;
+------------------------+--------+
| x                      | result |
+------------------------+--------+
| I am from Kansas       |      1 |
| Kansas State is great  |      0 |
| Kansas is a state      |      1 |
| Kansas Kansas State    |      1 |
| Kansas State vs Kansas |      1 |
| I'm from Kansas State  |      0 |
| KansasState            |      1 |
+------------------------+--------+
7 rows in set (0.00 sec)

【讨论】:

  • 哈!谢谢!我喜欢你证明它适用于所有示例的方式!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-06-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-05
相关资源
最近更新 更多