RegEx用于从两端删除非ASCII字符

时间:2019-05-10 00:47:02

标签: python regex python-2.7 regex-group regex-greedy

我必须使用此代码多次循环,是否有更好的方法?

@EnableMongoRepositories

@Configuration

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

类中

4 个答案:

答案 0 :(得分:10)

This expression不受左侧限制,如果所有所需的字符都与问题中的示例相似,则速度可能更快:

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

我假设您可能只想过滤输入字符串左右两侧的特殊字符。

您可以在此表达式中添加更多字符和边界,如果愿意,甚至可以将其更改为更简单,更快的表达式。

enter image description here

RegEx描述图

此图显示了表达式的工作方式,您可以在此link中可视化其他表达式:

enter image description here

如果您想在右侧添加边界,只需执行以下操作:

([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代码段使用简单的100万次for循环来显示该表达式的性能。

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测试

# coding=utf8
# the above tag defines encoding for this document and is for Python 2.x compatibility

import re

regex = r"([a-z0-9;.-]+)(.*)$"

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

matches = re.finditer(regex, test_str, re.MULTILINE)

for matchNum, match in enumerate(matches, start=1):

    print ("Match {matchNum} was found at {start}-{end}: {match}".format(matchNum = matchNum, start = match.start(), end = match.end(), match = match.group()))

    for groupNum in range(0, len(match.groups())):
        groupNum = groupNum + 1

        print ("Group {groupNum} found at {start}-{end}: {group}".format(groupNum = groupNum, start = match.start(groupNum), end = match.end(groupNum), group = match.group(groupNum)))

# Note: for Python 2.7 compatibility, use ur"" to prefix the regex and u"" to prefix the test string and substitution.

输出

Match 1 was found at 4-27: abc-123-4;5.def)(*&^;\n
> Group 1 found at 4-19: abc-123-4;5.def
Group 2 found at 19-27: )(*&^;\n

答案 1 :(得分:5)

您可以通过在字符集的开头使用克拉^字符来取反其内容来完成此操作。 [^a-zA-Z0-9]将匹配任何非字母或数字的内容。

^[^a-zA-Z0-9]+|[^a-zA-Z0-9]+$

答案 2 :(得分:4)

从开始/结束处修剪非单词字符\W的上方),并添加属于单词字符 [A-Za-z0-9_]的下划线可以将_\W一起放到character class中。

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

See demo at regex101。这与@CAustin的答案和@sln的评论非常相似。


要求逆并匹配从第一个到最后一个字母数字字符的所有内容:

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

使用re.DOTALL表示多行字符串。正则表达式无需尝试[\s\S]* instead of .*

Another demo at regex101|[^\W_]用于其中包含just one alnum的字符串。

答案 3 :(得分: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)

See explanation...

enter image description here

Here you can visualize your regular expression...