RegEx для удаления не ASCII символов с обоих концов - PullRequest
11 голосов
/ 10 мая 2019

Я должен сделать цикл несколько раз, используя этот код, есть ли лучший способ?

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]

Ответы [ 4 ]

10 голосов
/ 10 мая 2019

Это выражение не ограничено слева, и это может быть быстрее, если все ваши желаемые символы аналогичны примеру, который у вас есть в вашем вопросе:

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

Я предположил, что вы можете просто отфильтровать специальные символы в левой и правой части ваших входных строк.

Вы можете добавить больше символов и границ к этому выражению, и вы можете даже изменить его на более простое и быстрое выражение, если хотите.

enter image description here

Описательный график RegEx

Этот график показывает, как будет работать выражение, и вы можете визуализировать другие выражения в этой ссылке :

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 показывает производительность этого выражения с использованием простого цикла 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 Test

# 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

7 голосов
/ 17 мая 2019

Вы можете сделать это, используя символ карат ^ в начале набора символов, чтобы отрицать его содержимое.[^a-zA-Z0-9] будет соответствовать всему, что не является буквой или цифрой.

^[^a-zA-Z0-9]+|[^a-zA-Z0-9]+$
5 голосов
/ 18 мая 2019

Чтобы обрезать несловные символы (верхний \W) от начала / конца, но также добавить подчеркивание, которое принадлежит словесным символам [A-Za-z0-9_], вы можете опустить _в класс символов вместе с \W.

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

См. демонстрацию в regex101 .Это очень похоже на ответ @ CAustin и комментарий @ sln.


Чтобы получить обратную demo и сопоставить все от первого до последнего буквенно-цифрового символа:

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

Или с чередованием demo (|[^\W_] для строк, содержащих только один alnum в нем).

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

Оба с re.DOTALL для многострочных строк.Regex вкусы без попытки [\s\S]* вместо .* демо

3 голосов
/ 18 мая 2019

Прежде всего, вы можете отключить некоторые очень особые случаи, удалив escape-символы :

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)

См. Объяснение ...

enter image description here

Здесь вы можете визуализировать свое регулярное выражение ...

...