Как исключить строку из re.findall?
Это может быть глупый вопрос, но я просто пытаюсь учиться!
Я пытаюсь создать простой инструмент поиска по электронной почте, чтобы узнать больше о Python. Я изменяю некоторый открытый исходный код, чтобы разобрать адрес электронной почты:
emails = re.findall(r'([A-Za-z0-9\.\+_-]+@[A-Za-z0-9\._-]+\.[a-zA-Z]*)', html)
Затем я записываю результаты в электронную таблицу, используя модуль CSV.
Поскольку я хочу оставить расширение домена доступным практически для любого, мои результаты выводят файлы изображений в формате электронной почты:
пример: forbes@2x-302019213j32.png
Как я могу добавить, чтобы исключить строку "png" из re.findall
Код:
def scrape(self, page): try: request = urllib2.Request(page.url.encode("utf8")) html = urllib2.urlopen(request).read() except Exception, e: return emails = re.findall(r'([A-Za-z0-9\.\+_-]+@[A-Za-z0-9\._-]+\.[a-zA-Z]*)', html) for email in emails: if email not in self.emails: # if not a duplicate self.csvwriter.writerow([page.title.encode('utf8'), page.url.encode("utf8"), email]) self.emails.append(email)
3 ответа
Вы уже действуете только в случае if ... просто включите проверку if ... ... это будет намного проще, чем пытаться исключить его из регулярного выражения
if email not in self.emails and not email.endswith("png"): # if not a duplicate
self.csvwriter.writerow([page.title.encode('utf8'), page.url.encode("utf8"), email])
self.emails.append(email)
Есть много способов сделать это, но мой любимый это:
pat = re.compile(r'''
[A-Za-z0-9\.\+_-]+ # 1+ \w\n.+-_
@[A-Za-z0-9\._-]+ # literal @ followed by same
\.png # if png, DON'T CAPTURE
|([A-Za-z0-9\.\+_-]+@[A-Za-z0-9\._-]+\.[a-zA-Z]*)
# if not png, CAPTURE''', flags=re.X)
Поскольку регулярные выражения вычисляются слева направо, если строка начинает совпадать, то она будет соответствовать левой стороне |
первый. Если строка заканчивается .png
тогда он будет использовать эту строку, но НЕ перехватывать ее. Если это не заканчивается .png
правая сторона |
начнет потреблять это и будет захватывать это. Для более глубокого разговора об этой уловке, смотрите здесь. Чтобы использовать это сделать:
matches = filter(None,pat.findall(html))
Любая строка соответствует левой стороне (например, все png
файлы, которые совпадают, но НЕ являются частью группы захвата), будут отображаться как пустая строка в вашем findall. filter(None, iterable
) удаляет все пустые строки из вашей итерации, оставляя вам только те данные, которые вы хотите.
Кроме того, вы можете фильтровать после того, как вы захватите все
pat = re.compile(r'''[A-Za-z0-9\.\+_-]+@[A-Za-z0-9\._-]+\.[a-zA-Z]*''')
# same regex you have currently
matches = filter(lambda x: not x.endswith('png'), pat.findall(html))
Обратите внимание, что в дальнейшем вы должны сделать self.emails
множество. Похоже, что нет необходимости сохранять его порядок, и поиск по порядку намного быстрее, чем поиск по списку. Не забудьте использовать set.add
вместо list.append
хоть.
Я знаю, что Джоран уже дал вам ответ, но вот еще один способ сделать это с помощью регулярного выражения Python, который я нашел классным.
E сть (?!...)
шаблон сопоставления, который по существу говорит: "Где бы вы ни разместили этот шаблон сопоставления, если в этой точке строки проверяется этот шаблон и обнаруживается совпадение, то это совпадение не выполняется".
Если это плохое объяснение, документ Python делает работу намного лучше: https://docs.python.org/2/howto/regex.html
Также вот рабочий пример:
y = r'([A-Za-z0-9\.\+_-]+@[A-Za-z0-9\._-]+\.(?!png)[a-zA-z]*)'
s = 'forbes@2x-302019213j32.png'
re.findall(y, s) # Will return an empty list
s2 = 'myname@email2018529391230.net'
re.findall(y, s2) # Will return a list with s2 string
s3 = s + ' ' + s2 # Concatenates the two e-mail-formatted strings
re.findall(y, s3) # Will only return s2 string in list