Совпадение символа * в конце границы слова \ b - PullRequest
1 голос
/ 12 октября 2019

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

Используя набор строк, я строю слово OR. регулярное выражение границы:

import re

PHRASES = (
    'sh\\*t',  # easy
    'sh\\*\\*',  # difficult
    'f\\*\\*k',  # easy
    'f\\*\\*\\*',  # difficult
)

MATCHER = re.compile(
    r"\b(%s)\b" % "|".join(PHRASES), 
    flags=re.IGNORECASE | re.UNICODE)

Проблема в том, что * не может быть обнаружен рядом с границей слова \b.

print(MATCHER.search('Well f*** you!'))  # Fail - Does not find f***
print(MATCHER.search('Well f***!'))  # Fail - Does not find f***
print(MATCHER.search('f***'))  # Fail - Does not find f***
print(MATCHER.search('f*** this!'))  # Fail - Does not find f***
print(MATCHER.search('secret code is 123f***'))  # Pass - Should not match
print(MATCHER.search('f**k this!'))  # Pass - Should find 

Любые идеи по настройкеэто удобно для поддержки фраз, заканчивающихся специальными символами?

Ответы [ 4 ]

5 голосов
/ 28 октября 2019

* не является символом слова , следовательно, не обозначается, если за ним следуют \ b и несловный символ .

Предполагая, что начальная граница слова в порядке, но вы хотите соответствовать sh*t, но не sh*t* или совпадению f***!, но не f***a как насчет имитации вашего собственного словаГраница с использованием отрицательного Lookahead .

\b(...)(?![\w*])

См. эту демонстрацию в regex101

При необходимости, начальное слово границы \bможет быть заменено отрицательным взглядом: (?<![\w*])

1 голос
/ 12 октября 2019

Используйте свои знания о начале и окончании фраз и используйте их с соответствующими сопоставителями.
Вот статическая версия, но легко отсортировать входящие новые фразы автоматически по началу и окончанию.

import re

PHRASES1 = (
    'sh\\*t',  # easy
    'f\\*\\*k',  # easy
)
PHRASES2 = (
    'sh\\*\\*',  # difficult
    'f\\*\\*\\*',  # difficult
)
PHRASES3 = (
    '\\*\\*\\*hole', 
)
PHRASES4 = (
    '\\*\\*\\*sonofa\\*\\*\\*\\*\\*',  # easy
)
MATCHER1 = re.compile(
    r"\b(%s)\b" % "|".join(PHRASES1), 
    flags=re.IGNORECASE | re.UNICODE)
MATCHER2 = re.compile(
    r"\b(%s)[$\s]" % "|".join(PHRASES2), 
    flags=re.IGNORECASE | re.UNICODE)
MATCHER3 = re.compile(
    r"[\s^](%s)\b" % "|".join(PHRASES3), 
    flags=re.IGNORECASE | re.UNICODE)
MATCHER4 = re.compile(
    r"[\s^](%s)[$\s]" % "|".join(PHRASES4), 
    flags=re.IGNORECASE | re.UNICODE)
1 голос
/ 12 октября 2019

Может встраивать требования к границе в каждую строку, например

'\\bsh\\*t\\b', 
'\\bsh\\*\\*',  
'\\bf\\*\\*k\\b',  
'\\bf\\*\\*\\*', 

, затем r"(%s)" % "|".join(PHRASES)

Или, если механизм регулярных выражений поддерживает условные выражения, он выполняется следующим образом

'sh\\*t', 
'sh\\*\\*',  
'f\\*\\*k',  
'f\\*\\*\\*', 

затем r"(?(?=\w)\b)(%s)(?(?<=\w)\b)" % "|".join(PHRASES)

0 голосов
/ 29 октября 2019

Я не совсем понимаю ваше утверждение, что * - это не то, что можно найти рядом с границей слова. Тем не менее, если я правильно понимаю, что вы ищете из комментариев, я думаю, что это сработает:

\b[\w]\*+[\w]*
  • Граница слова
  • За ним следует какая-то буква, например f
  • После одного или нескольких *
  • При желании оканчивается какой-либо буквой, например k

Пример:

https://regexr.com/4nqie

...