正则表达式匹配带有标点的单词,但不是单独的标点
Posted
技术标签:
【中文标题】正则表达式匹配带有标点的单词,但不是单独的标点【英文标题】:Regex to match words with punctuation but not punctuation alone 【发布时间】:2017-02-03 07:48:02 【问题描述】:我需要匹配字符串中可能包含符号的单词,既在单词中也作为标点符号。示例字符串可能是:
This string's is a good example of situation I'll fail to match - due to punctuations being all over the place.
忽略那句奇怪的英语,我有一个案例,我需要匹配每个单词,而不是标点符号,除非它是单词的一部分。所以我的结果应该是
-
这个
字符串(匹配
's
,因为它是单词的一部分)
是
一个
好
...
-
我会(将
'll
与 I 匹配,因为它是单词的一部分)
失败
到
匹配
到期(跳过-
)
到
...
-
place(没有句号,因为它不是单词的一部分。)
我设法想出了两个部分有效但都不能按我想要的方式工作的正则表达式
(?<=\\s|^)[A-Za-z0-9]+?(?=\\s|$) - I am using swift so `\\s` is for whitespace
这匹配普通单词,但不匹配 string's
这样的情况,因为单词中有 '
。但如果我使用我的其他表达方式:
(?<=\\s|^).+?(?=\\s|$)
它匹配string's
,但也匹配-
和句尾的句号,如place.
是否有一个表达式可以匹配带有标点符号但不单独标点符号的单词?我不介意是否需要多个表达式来捕获所有结果,我可以在显示之前合并结果。
注意:除了给出的示例之外,我知道的标点符号既可以作为单词的一部分存在,也可以不包括-
'
()
.
,而仅作为单词一部分的标点符号包括@ 987654336@ $
#
&
/
可以假定任何其他标点符号永远不会成为任何单词的一部分。 !
?
"
:
应在单词中出现或不出现空格,但不得与结果匹配。
幸运的是,可以安全地假设该字符串仅包含字母数字和标点符号 - 可以假设其他语言字符和符号,如 <>[]|
或 +*=
不会出现在字符串中 - 还有一些其他符号适合我现在无法预测的四组符号之一,但我相信如果我能得到一个可行的逻辑,我可以调整它以在每组中包含更多符号。
【问题讨论】:
【参考方案1】:您似乎需要一个正则表达式,它能够匹配前面或后面带有“单词”字符的选定符号,或者只是字母/数字或括号字母/数字。所有这些都应该在空格、字符串位置的开始/结束或单词边界内(注意这个顺序很重要)。
使用
(?<=\\s|^|\\b)(?:[-'.%$#&/]\\b|\\b[-'.%$#&/]|[A-Za-z0-9]|\\([A-Za-z0-9]+\\))+(?=\\s|$|\\b)
请参阅regex demo。
详情:
(?<=\\s|^|\\b)
- 一个正向的向后看,要求当前位置左侧必须有空格、字符串开头或单词边界
(?:
- 非捕获组的开始,匹配 1+ 个序列:
[-'.%$#&/]\\b
- 指定的符号后跟一个单词 char
|
- 或
\\b[-'.%$#&/]
- 指定的符号前面有一个单词 char
|
- 或
[A-Za-z0-9]
- 一个字母数字
|
- 或
\\([A-Za-z0-9]+\\)
- (
,后跟 1+ 个字母数字符号和 )
)+
- 非捕获组结束
(?=\\s|$|\\b)
- 正向前瞻要求在当前位置的右侧必须有空格、字符串结尾或单词边界。
要仅匹配点作为小数分隔符,请添加一个额外的 \d*\.?\d+
分支并从字符类中取出 .
:
(?<=\\s|^|\\b)(?:[-'%$#&/]\\b|\\b[-'%$#&/]|\\d*\\.?\\d+|[A-Za-z0-9]|\\([A-Za-z0-9]+\\))+(?=\\s|$|\\b)
见this regex demo
【讨论】:
我想直接编辑答案,但它说至少需要更改 6 个字符。如果您从\\b[-'.%$#&/]
中删除.
,则句尾的句号将不匹配,稍微更准确地满足我的需要。制作完整的表达式(?<=\\s|^|\\b)(?:[-'.%$#&/]\\b|\\b[-'%$#&/]|[A-Za-z0-9]|\\([A-Za-z0-9]+\\))+(?=\\s|$|\\b)
。当我设法进一步改进它时,我会更新。
好吧,从你之前的cmets来看,如果是小数分隔符,只需要匹配一个点即可。然后使用this regex。但是请注意,点也不会与Dr.
等缩写匹配。然后,您必须在附加分支中列出所有带有点的缩写。【参考方案2】:
假设一个单词最多有一个标点符号,你可以试试:
(?<=\\s|^) ([A-Za-z0-9]+? | [A-Za-z0-9]*?[\-\'\(\)\.\%\$\#\&\/][A-Za-z0-9]*? ) (?=\\s|$)
但 Wiktor Stribiżew 解决方案更好:
(?<=\\s|^|\\b)(?:[-'.%$#&/]\\b|\\b[-'.%$#&/]|[A-Za-z0-9]|\\([A-Za-z0-9]+\\))+(?=\\s|$|\\b)
【讨论】:
对不起,这个假设不正确。你的回答让我更进一步,但是有像apple(s)
这样的词必须匹配两个括号,而 (else?)
只有 else
匹配。像$13.30
这样的数字也将被匹配为一个单词。我遇到过的最棘手的正则表达式。
你试试第二个吗?
我删除了那个 ((?<=\\s|^)[A-Za-z0-9]+(?:[\-\'\(\)\.\%\$\#\&\/][A-Za-z0-9]+)*(?=\\s|$)
),它不适用于上述评论中的情况。顺便说一句,你的过度逃避看起来不太好。所有这些符号都不是字符类中的特殊字符,-
在字符类的开头也不是特殊字符。
已编辑!是的,如果单词以标点符号开头,则第一个不匹配
为了避免自动上色失败,我越界了【参考方案3】:
如果标点符号后面总是没有单词,例如 coma then space 或 dash then space,你可以使用这个正则表达式\W2,
吗?
注意: \W 匹配任何非单词字符(等于 [^a-zA-Z0-9_]) 2, 量词 - 匹配 2 次到无限次
【讨论】:
我想你误会了,我试图匹配带有或不带有符号的单词,而不是符号本身。 啊,我很抱歉,但如果你想要,你需要首先定义你定义为标点符号的规则。例如,如果您添加诸如“此 50% 折扣”之类的内容,您接受的答案仍然不匹配,因为它与“匹配匹配,到期”具有相同的模式,因为要求总是在增长。(但您接受的新答案可以:D) 好收获!但正如你所看到的,答案中的表达式已经非常复杂,足以涵盖最常见的情况。我相信从这里开始是公平的,我自己努力解决剩下的例外情况。非常感谢您帮助我们找出该表达的缺失。以上是关于正则表达式匹配带有标点的单词,但不是单独的标点的主要内容,如果未能解决你的问题,请参考以下文章