Python正则表达式用于匹配重复标点符号和符号

1 投票
4 回答
3772 浏览
提问于 2025-04-17 14:23

我需要一个正则表达式,可以匹配重复的标点符号和符号。也就是说,所有重复的非字母数字和非空格的字符,比如……、???、!!!、###、@@@、+++等等。必须是同一个字符重复,而不是像“!?@”这样的组合。

我试过 [^\s\w]+,虽然它能匹配到所有的!!!、???、$$$的情况,但它匹配的内容比我想要的还要多,因为它也会匹配“!?@”。

有人能帮我解答一下吗?谢谢。

4 个回答

1

编辑:@Firoze Lafeer 提出了一个答案,使用一个正则表达式就能完成所有操作。我会保留这个内容,以防有人对将正则表达式和过滤功能结合起来感兴趣,但对于这个问题,使用 Firoze Lafeer 的答案会更简单、更快。

在我看到 Firoze Lafeer 的答案之前写的回答如下,未做更改。

一个简单的正则表达式无法做到这一点。经典的总结是“正则表达式无法计数”。这里有讨论:

如何使用正则表达式检查一个字符串是否是回文?

对于 Python 的解决方案,我建议将正则表达式和一些 Python 代码结合起来。正则表达式会过滤掉所有不是某种标点符号连续出现的内容,然后 Python 代码会检查并排除错误匹配(即虽然是标点符号的连续出现,但并不是同一种字符)。

import re
import string

# Character class to match punctuation.  The dash ('-') is special
# in character classes, so put a backslash in front of it to make
# it just a literal dash.
_char_class_punct = "[" + re.escape(string.punctuation) + "]"

# Pattern: a punctuation character followed by one or more punctuation characters.
# Thus, a run of two or more punctuation characters.
_pat_punct_run = re.compile(_char_class_punct + _char_class_punct + '+')

def all_same(seq, basis_case=True):
    itr = iter(seq)
    try:
        first = next(itr)
    except StopIteration:
        return basis_case
    return all(x == first for x in itr)

def find_all_punct_runs(text):
    return [s for s in _pat_punct_run.findall(text) if all_same(s, False)]


# alternate version of find_all_punct_runs() using re.finditer()
def find_all_punct_runs(text):
    return (s for s in (m.group(0) for m in _pat_punct_run.finditer(text)) if all_same(s, False))

我写的 all_same() 函数是为了让它在迭代器和字符串上都能正常工作。Python 内置的 all() 对于空序列会返回 True,但我们在这个特定情况下并不想要这样,所以我为期望的基础情况设置了一个参数,并将其默认值设为 True,以匹配 all() 的行为。

这个方法尽可能多地利用了 Python 的内部机制(正则表达式引擎或 all()),所以应该会比较快。对于较大的输入文本,你可能想要重写 find_all_punct_runs(),使用 re.finditer() 而不是 re.findall()。我给了一个例子。这个例子还返回了一个生成器表达式,而不是一个列表。你总是可以强制它生成一个列表:

lst = list(find_all_punct_runs(text))
2

我觉得你可能在寻找这样的东西:

[run for run, leadchar in re.findall(r'(([^\w\s])\2+)', yourstring)]

举个例子:

In : teststr = "4spaces    then(*(@^#$&&&&(2((((99999****"

In : [run for run, leadchar in re.findall(r'(([^\w\s])\2+)',teststr)]
Out: ['&&&&', '((((', '****']

这个代码会给你一个列表,里面包含了连续的字符,但会把字符串中的4个空格和像'*(@^'这样的序列排除掉。

如果这不是你想要的结果,你可以修改一下你的问题,提供一个示例字符串,并明确你希望看到的输出是什么。

2

试试这个模式:

([.\?#@+,<>%~`!$^&\(\):;])\1+

\1 是指第一个匹配到的组,也就是括号里的内容。

你需要根据需要扩展标点符号和符号的列表。

撰写回答