正则表达式:如何匹配所有非字母字符,无论它们在字符串中的什么位置?

Regex: How do I match all non letter characters no matter where they are in the string?

我不确定是否有一个优雅的解决方案。正则表达式应该只考虑搜索字符串中的字母,并且另外匹配所有其他字符,无论它们出现在搜索字符串字符之间的什么位置,例如:

搜索字符串 My Moms house 应与 -> <- 标记的段相匹配:

text 123 ->My Mom's house<- jidjio

bla bla ->My8Mo2ms231#43house<- bla bla

Test string ->My Mom's' house<- further text

等等

匹配

所以,从你的问题来看,我相信你正在寻找这个

M.*?y.*?M.*?o.*?m.*?s.*?h.*?o.*?u.*?s.*?e

M[^a-zA-Z]*?y[^a-zA-Z]*?M[^a-zA-Z]*?o[^a-zA-Z]*?m[^a-zA-Z]*?s[^a-zA-Z]*?h[^a-zA-Z]*?o[^a-zA-Z]*?u[^a-zA-Z]*?s[^a-zA-Z]*?e

第一个匹配搜索字符串加上搜索字符串字符之间的任何字符(如问题正文中所述,请参阅 regex101), the second one does the same for non-alphabetic characters (as your question title suggests, see regex101)。

其中每一个都是根据搜索字符串的字符构建的,具有一种模式以延迟匹配任何字符(案例 1)或任何非字母字符(案例 2)。

注意:如果您希望第二个也排除“特殊”单词字符,例如éüô,您需要在您使用的正则表达式模式中相应地处理它们,例如通过使用 unicode 类别 \P{L}.

M\P{L}*?y\P{L}*?M\P{L}*?o\P{L}*?m\P{L}*?s\P{L}*?h\P{L}*?o\P{L}*?u\P{L}*?s\P{L}*?e

\p{L} 匹配类别“字母”中的单个代码点,\P{L} 匹配相反的代码点(参见 regex101)。

构建表达式

无论您的确切表达式是什么,您都可以通过将搜索字符串的每个字符与您选择的表达式连接起来来轻松构建最终的正则表达式字符串,以匹配两者之间的内容。

Python 例子

这是一个 python 示例(因为您的问题没有用编程语言标记):

import regex

text = ["text 123 ->My Mom's house<- jidjio", 
        "bla bla ->My8Mo2ms231#43house<- bla bla", 
        "Test string ->My Mom's' house<- further text", 
        "wkashhasMdykMomLsfheoousssswQseBswenksd", 
        "textMy?M?om*s?*hou?*seorsomethingelse",
        "thisIs3MôyMäoméshouseEFSAcasw!"]

search_string = "MyMomshouse"

regex_string = r'.*?'.join(str(c) for c in search_string)
regex_string2 = r'[^a-zA-Z]*?'.join(str(c) for c in search_string)
regex_string3 = r'\P{L}*?'.join(str(c) for c in search_string)

print('\n--- regex 1 ---')
for t in text:
    print(regex.search(regex_string, t))

print('\n--- regex 2 ---')
for t in text:
    print(regex.search(regex_string2, t))

print('\n--- regex 3 ---')
for t in text:
    print(regex.search(regex_string3, t))

输出:


--- regex 1 ---
<regex.Match object; span=(11, 25), match="My Mom's house">
<regex.Match object; span=(10, 29), match='My8Mo2ms231#43house'>
<regex.Match object; span=(14, 29), match="My Mom's' house">
<regex.Match object; span=(8, 31), match='MdykMomLsfheoousssswQse'>
<regex.Match object; span=(4, 22), match='My?M?om*s?*hou?*se'>
<regex.Match object; span=(7, 21), match='MôyMäoméshouse'>

--- regex 2 ---
<regex.Match object; span=(11, 25), match="My Mom's house">
<regex.Match object; span=(10, 29), match='My8Mo2ms231#43house'>
<regex.Match object; span=(14, 29), match="My Mom's' house">
None
<regex.Match object; span=(4, 22), match='My?M?om*s?*hou?*se'>
<regex.Match object; span=(7, 21), match='MôyMäoméshouse'>

--- regex 3 ---
<regex.Match object; span=(11, 25), match="My Mom's house">
<regex.Match object; span=(10, 29), match='My8Mo2ms231#43house'>
<regex.Match object; span=(14, 29), match="My Mom's' house">
None
<regex.Match object; span=(4, 22), match='My?M?om*s?*hou?*se'>
None

注意:

  • 我使用 python regex 模块而不是 re 模块,因为它支持 \p{L} 模式。
  • 如果您的搜索字符串包含在正则表达式中具有特殊含义的字符,您需要在构建模式时对它们进行转义,例如'.*?'.join(regex.escape(str(c)) for c in search_string)
  • 我使用了搜索字符串 MyMomshouse(无空格)而不是您指定的字符串,因为您的字符串在第二个示例字符串中不匹配。

JavaScript 示例:

在 JavaScript 中,或者原则上,在任何语言中都是可能的。另见 this JS fiddle:

const text = ["text 123 ->My Mom's house<- jidjio", 
        "bla bla ->My8Mo2ms231#43house<- bla bla", 
        "Test string ->My Mom's' house<- further text", 
        "wkashhasMdykMomLsfheoousssswQseBswenksd", 
        "textMy?M?om*s?*hou?*seorsomethingelse",
        "thisIs3MôyMäoméshouseEFSAcasw!"];
      
const search_string = "MyMomshouse";

const regex_string = Array.from(search_string).join('.*?')

console.log(regex_string)

text.forEach((entry) => {
    console.log(entry.search(regex_string));
});

然而,unicode 字符组支持并不总是可用,请参阅 this SO questions and its answers for possible solutions