去除两端非ASCII字符的正则表达式

11

我必须使用这段代码多次循环,有更好的方法吗?

item = '!@#$abc-123-4;5.def)(*&^;\n'

或者

'!@#$abc-123-4;5.def)(*&^;\n_'

或者

'!@#$abc-123-4;5.def)_(*&^;\n_'

我有一个像这样的,但它不起作用

item = re.sub('^\W|\W$', '', item)

期望

abc-123-4;5.def

最终目标是仅保留两端的任何非[a-zA-Z0-9]字符,同时保留中间的任何字符。第一个和最后一个字母在类[a-zA-Z0-9]中。

2
不确定你为什么要循环多次。你是指在同一个输入字符串上吗?^\W+|\W+$ - CAustin
3
使用 ^\W+|\W+$。该正则表达式用于匹配一个字符串开头和结尾处的非单词字符。 - user557597
@CAustin @sin 谢谢,这是加号 +,我使用了一个递归函数,我以为它应该是错误的,谢谢! - Gang
2
在标题中,“删除非ASCII字符”是什么意思?这些是ASCII字符:!@#$ - Norbert Incze
2
您的标题应该是“使用正则表达式从两端删除非单词字符” - Norbert Incze
显示剩余3条评论
4个回答

13
这个表达式左边没有界限,如果你所需的字符与你在问题中提供的示例类似,则它可能会更快。

该表达式左侧没有边界限制,如果所需字符与您在问题中提供的示例相似,则其性能可能更快:

([a-z0-9;.-]+)(.*)

这里,我们假设您只想过滤输入字符串左右两侧的特殊字符。

您可以在表达式中包含其他字符和边界,并且如果愿意,甚至可以将其修改/更改为更简单且更快速的表达式。

输入图像描述

RegEx 描述性图形

此图显示了该表达式的工作方式,并且您可以在此链接中可视化其他表达式:

输入图像描述

如果您希望在右侧添加其他边界,只需这样做:

([a-z0-9;.-]+)(.*)$

甚至你可以将特殊字符列在捕获组的左侧和右侧。

JavaScript测试

const regex = /([a-z0-9;.-]+)(.*)$/gm;
const str = `!@#\$abc-123-4;5.def)(*&^;\\n`;
let m;

while ((m = regex.exec(str)) !== null) {
    // This is necessary to avoid infinite loops with zero-width matches
    if (m.index === regex.lastIndex) {
        regex.lastIndex++;
    }
    
    // The result can be accessed through the `m`-variable.
    m.forEach((match, groupIndex) => {
        console.log(`Found match, group ${groupIndex}: ${match}`);
    });
}

性能测试

这段 JavaScript 代码片段使用简单的循环来展示该表达式的性能。

const repeat = 1000000;
const start = Date.now();

for (var i = repeat; i >= 0; i--) {
 const string = '!@#\$abc-123-4;5.def)(*&^;\\n';
 const regex = /([!@#$)(*&^;]+)([a-z0-9;.-]+)(.*)$/gm;
 var match = string.replace(regex, "$2");
}

const end = Date.now() - start;
console.log("YAAAY! \"" + match + "\" is a match  ");
console.log(end / 1000 + " is the runtime of " + repeat + " times benchmark test.  ");

Python测试

import re

regex = r"([a-z0-9;.-]+)(.*)$"
test_str = "!@#$abc-123-4;5.def)(*&^;\\n"
print(re.findall(regex, test_str))

输出

[('abc-123-4;5.def', ')(*&^;\\n')]

1
你忘记了右边界,而且我认为你不需要捕获第一部分,因为它将被丢弃。 - Mad Physicist
2
假设([a-z0-9;.-]+)(.*)^\W+|\W+$的相反面是一个概念上的错误。实际上,它的相反面是(\w(?:.*\w)?),其中$1将成为新字符串。https://regex101.com/r/ySNdja/2 - user557597
1
我并不是在试图表现得更好,只是指出了一个缺陷,只是想要帮忙... - user557597
1
Emma,为什么你要删除所有的评论?这样会让跟帖变得困难。 - Alex Gordon
1
@Emma 这有点烦人。 - Alex Gordon
显示剩余2条评论

9
您可以使用插入符号 ^ 来对字符集进行否定,从而达到此目的。例如,[^a-zA-Z0-9] 可以匹配除字母或数字外的任何字符。
^[^a-zA-Z0-9]+|[^a-zA-Z0-9]+$

6

如果您想剪辑开头/结尾的非单词字符(即大写\W),但也要添加属于单词字符[A-Za-z0-9_]的下划线,您可以将_\W一起放入字符类中。

^[\W_]+|[\W_]+$

在regex101上查看演示。这与@CAustin的答案和@sln的评论非常相似。


获取反演演示并匹配从第一个到最后一个字母数字字符的所有内容:

[^\W_](?:.*[^\W_])?

或使用交替 演示|[^\W_] 用于字符串中只有一个字母数字字符)。

[^\W_].*[^\W_]|[^\W_]

对于多行字符串,都要使用re.DOTALL。没有try的正则表达式会使用[\s\S]*代替.*演示


3

首先,您可以通过去除转义字符来排除一些非常特殊的情况:

item = re.sub(r'\\[abnrt]', '', item)

接下来我们将从 \W 中删除下划线_字符,将得到 [^a-zA-Z0-9]

您的最终正则表达式将是:(^[^a-zA-Z0-9]+)|([^a-zA-Z0-9]+$)

item = re.sub(r'(^[^a-zA-Z0-9]+)|([^a-zA-Z0-9]+$)', '', item)

查看解释...

在此输入图片描述

您可以在此处可视化您的正则表达式...


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接