Как заменить все символы, кроме букв, цифр, прямой и обратной косой черты

Хотите проанализировать текст и вернуть только буквы, цифры, прямую и обратную косую черту и заменить все остальное на ''.

Можно ли использовать только один шаблон регулярного выражения, а не несколько, которые затем вызывают цикл? Я не могу получить приведенный ниже шаблон, чтобы не заменить обратную и прямую косую черту.

line1 = "1/R~e`p!l@@a#c$e%% ^A&l*l( S)-p_e+c=ial C{har}act[er]s ;E  xce|pt Forw:ard\" $An>d B,?a..ck Sl'as<he#s\\2"
line2 = line
RGX_PATTERN = "[^\w]", "_"

for pattern in RGX_PATTERN:
    line = re.sub(r"%s" %pattern, '', line)
print("replace1: " + line)
#Prints: 1ReplaceAllSpecialCharactersExceptForwardAndBackSlashes2

приведенный ниже код из SO был протестирован и оказался быстрее, чем регулярное выражение, но затем он заменяет все специальные символы, включая / и \ что я хочу сохранить. Есть ли способ отредактировать его, чтобы он работал для моего варианта использования и при этом сохранял преимущество над регулярным выражением?

line2 = ''.join(e for e in line2 if e.isalnum())
print("replace2: " + line2)
#Prints: 1ReplaceAllSpecialCharactersExceptForwardAndBackSlashes2

В качестве дополнительного препятствия синтаксический анализ текста должен быть в форме ASCII, поэтому, если возможно, символы из любой другой кодировки также следует заменить на ''


person lukik    schedule 08.05.2014    source источник


Ответы (2)


Немного быстрее и работает для Unicode:

full_pattern = re.compile('[^a-zA-Z0-9\\\/]|_')

def re_replace(string):
    return re.sub(full_pattern, '', string)

Если вы хотите, чтобы это было действительно быстро, это, безусловно, лучший (но немного неясный) метод:

def wanted(character):
    return character.isalnum() or character in '\\/'

ascii_characters = [chr(ordinal) for ordinal in range(128)]
ascii_code_point_filter = [c if wanted(c) else None for c in ascii_characters]

def fast_replace(string):
    # Remove all non-ASCII characters. Heavily optimised.
    string = string.encode('ascii', errors='ignore').decode('ascii')

    # Remove unwanted ASCII characters
    return string.translate(ascii_code_point_filter)

Тайминги:

SETUP="
busy = ''.join(chr(i) for i in range(512))

import re
full_pattern = re.compile('[^a-zA-Z0-9\\\/]|_')

def in_whitelist(character):
    return character.isalnum() or character in '\\/'

def re_replace(string):
    return re.sub(full_pattern, '', string)

def wanted(character):
    return character.isalnum() or character in '\\/'

ascii_characters = [chr(ordinal) for ordinal in range(128)]
ascii_code_point_filter = [c if wanted(c) else None for c in ascii_characters]

def fast_replace(string):
    string = string.encode('ascii', errors='ignore').decode('ascii')
    return string.translate(ascii_code_point_filter)
"

python -m timeit -s "$SETUP" "re_replace(busy)"
python -m timeit -s "$SETUP" "''.join(e for e in busy if in_whitelist(e))"
python -m timeit -s "$SETUP" "fast_replace(busy)"

Полученные результаты:

10000 loops, best of 3: 63 usec per loop
10000 loops, best of 3: 135 usec per loop
100000 loops, best of 3: 4.98 usec per loop
person Veedrac    schedule 08.05.2014
comment
производит точно такой же результат, как у меня для всех из них: - person Master_Yoda; 08.05.2014
comment
@Мастер_Йода; Вероятно, вы используете Python 2. OP использует Python 3. - person Veedrac; 08.05.2014
comment
Хороший звонок, раньше не замечал. - person Master_Yoda; 08.05.2014
comment
Протестировал это, и он заботится о тексте, отличном от ascii. - person lukik; 08.05.2014

Почему вы не можете сделать что-то вроде:

def in_whitelist(character):
    return character.isalnum() or character in ['\\','/']

line2 = ''.join(e for e in line2 if in_whitelist(e))

Отредактировано в соответствии с предложением сжать функцию.

person Master_Yoda    schedule 08.05.2014
comment
Я бы лично изменил последнюю часть на character in ['\', '/'] для краткости. - person Khaelex; 08.05.2014
comment
В порядке. Это сработало. Просто нужно было избежать обратной косой черты ['\\', '/'] - person lukik; 08.05.2014
comment
У меня сработало после экранирования строкового литерала... О, и @Khaelid, согласен. - person Master_Yoda; 08.05.2014
comment
Не удается выполнить все следующие действия: ª²³µ¹º¼½¾ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßàá (и т. д.) - person Veedrac; 08.05.2014