Как парсить строку в python
Перейти к содержимому

Как парсить строку в python

  • автор:

10 приемов для преобразования и декомпозиции строк в Python

В этой статье мы рассмотрим некоторые приемы для парсинга и токенизации строк в Python.

Никто не может отрицать важность анализа текста и синтаксического анализа строк. Он применяется практически во всех направлениях разработки программного обеспечения, от парсинга URL-адресов до обработки естественного языка. Мы не будем описывать все возможные его применения — это выходит далеко за рамки одной статьи. Но о некоторых базовых методах работы со строками и токенами в Python мы расскажем.

Эти маленькие скрипты следует рассматривать как строительные блоки для приложений для анализа текста и предварительной обработки данных. Знание основ очень важно для дальнейшего развития.

А теперь давайте перейдем к нашему списку!

1. Translate и Replace

Первый случай — заменить или удалить некоторые символы или подстроки из текста. В Python есть встроенные функции в модуле string, которые выполняют эти задачи.

Метод translate() использует таблицу (которая строится при помощи функции maketrans ) для удаления или изменения определенных символов:

test_string = 'The quick brown fox jumps over the lazy dog' translation_map = str.maketrans('eo', ' ') test_string.translate( translation_map ) Out[1]: 'Th quick br wn f x jumps v r th lazy d g'

Метод replace() работает так, как следует из его названия — изменяя подстроку на нужную:

test_string = 'The quick brown fox jumps over the lazy dog' test_string.replace( 'fox', 'squirell') Out[2]: 'The quick brown squirell jumps over the lazy dog'

2. Очистка строки

Теперь мы можем применить информацию из предыдущего пункта для очистки строки. Это один из наиболее востребованных процессов в проектах data science при очистке данных. Отличный пример — это необработанный текст с пробельными символами и переносами строк. Вот простой скрипт для очистки такой строки:

test_string_with_garbage = 'The quick brown fox\njumps\tover the\tlazy dog\r\n' character_map = < ord('\n') : ' ', ord('\t') : ' ', ord('\r') : None >test_string_with_garbage.translate(character_map) Out[3]: 'The quick brown fox jumps over the lazy dog '

3. Разбиение строки

Для анализа текста требуются различные метрики, такие как количество слов, количество символов, средняя длина предложения. Чтобы вычислить эти значения, нам нужно подготовить текст — очистить и разделить. К счастью для нас, в Python есть несколько встроенных функций для разделения текста:

  • Разбиение по пробелу (по умолчанию):
test_string.split() Out[1]: ['The', 'quick', 'brown', 'fox', 'jumps', 'over', 'the', 'lazy', 'dog']
  • Разбиение на определенное количество токенов:
test_string.split(' ', 2) Out[2]: ['The', 'quick', 'brown fox jumps over the lazy dog']
  • Разбиение на определенное количество токенов в обратном направлении:
test_string.rsplit(' ', 2) Out[3]: ['The quick brown fox jumps over the', 'lazy', 'dog']
  • Разбиение по произвольному символу:
test_string.split('e') Out[4]: ['Th', ' quick brown fox jumps ov', 'r the lazy dog']
  • Разбиение строки по нужному токену с токенами до и после него:
test_string.partition('fox') Out[5]: ('The quick brown ', 'fox', ' jumps over the lazy dog')

4. Strip и zfill

Еще одна важная функция — это возможность удалять из строки лишние начальные и конечные символы. Для этого у нас есть семейство функций strip() :

  • Удалить пробелы по умолчанию.
  • Удалить пробелы слева или справа.
  • Удалить произвольные символы.
test_string_with_spaces = ' The quick brown fox jumps over the lazy dog ' test_string_with_spaces.strip() Out[1]: 'The quick brown fox jumps over the lazy dog' test_string_with_spaces.lstrip() Out[2]: 'The quick brown fox jumps over the lazy dog ' test_string_with_spaces.rstrip() Out[3]: ' The quick brown fox jumps over the lazy dog' test_string.rstrip('g') Out[4]: 'The quick brown fox jumps over the lazy do'

Кроме того, есть полезная функция для дополнения чисел ведущими нулями:

'29'.zfill(10) Out[1]: '0000000029' 'xA1'.zfill(4) Out[2]: '0xA1'

5. Деконструкция и реконструкция

Для генерации текста необходимо построить предложения и фразы из словаря слов. Этот процесс обратный разделению строки. Python позволяет нам использовать встроенный строковый метод join() для объединения слов обратно в предложение:

test_array = test_string.split() # ['The', 'quick', 'brown', 'fox', 'jumps', 'over', 'the', 'lazy', 'dog'] ''.join(test_array) Out[1]: 'Thequickbrownfoxjumpsoverthelazydog' ' '.join(test_array) Out[2]: 'The quick brown fox jumps over the lazy dog'

6. Удаление знаков препинания

Это еще один случай очистки текста. Модуль string в Python имеет множество встроенных констант с отдельными наборами символов. string.punctuation — один из них, поэтому мы будем использовать его для очистки строки.

test_punctuation = " This &is [an] example? string. with.? punctuation. " import string test_punctuation.translate(str.maketrans('', '', string.punctuation)) Out[1]: 'This is an example of string with punctuation'

7. Работа с регистрами

Форматирование текста — это боль каждого data scientist’а. Слова и предложения в разных форматах создают много проблем при очистке данных. Однако и для этих задач в Python есть нужные функции:

test_string.lower() Out[1]: 'the quick brown fox jumps over the lazy dog' test_string.upper() Out[2]: 'THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG' test_string.title() Out[3]: 'The Quick Brown Fox Jumps Over The Lazy Dog' test_string.title().swapcase() Out[4]: 'tHE qUICK bROWN fOX jUMPS oVER tHE lAZY dOG' test_string.title().swapcase().capitalize() Out[5]: 'The quick brown fox jumps over the lazy dog'

8. Мир регулярных выражений

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

Мы не будем обсуждать всю мощь регулярных выражений, а сосредоточимся на их применении — например, на разделении и замене данных. Да, эти задачи были описаны выше, но вот более мощная альтернатива.

Разделение по шаблону:

import re test_punctuation = " This &is [an] example? string. with.? punctuation. " re.split('\W+', test_punctuation) Out[1]: ['This', 'is', 'an', 'example', 'of', 'string', 'with', 'punctuation', '']

Замена по шаблону:

import re test_with_numbers = "This is 1 string with 10 words for 9 digits 2 example" re.sub('\d', '*', test_with_numbers) Out[1]: 'This is * string with ** words for * digits * example'

9. Токенизация строки

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

import pandas as pd test_punctuation = " This &is [an] example? string. with.? punctuation. " data = pd.DataFrame([test_punctuation]) data.iloc[0].str.lower().str.replace('\W+', ' ').str.strip().str.split() Out[1]: [this, is, an, example, of, string, with, punctuation] Name: 0, dtype: object

10. Поиск подстроки

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

  • Заканчивается ли строка указанной подстрокой:
test_string.endswith('dog') Out[1]: True
  • Начинается ли строка с указанной подстроки:
test_string.startswith('dog') Out[2]: False
  • Содержит ли строка указанную подстроку:
'fox' in test_string Out[3]: True
  • Получение индекса подстроки:
test_string.find('fox') Out[4]: 16

Конечно, любую задачу можно решить множеством способов, особенно если мы говорим о Python. Однако мы думаем, что наше видение синтаксического анализа строк будет для вас полезным.

Как разделить строку по пробелам python

Такую задачу всегда можно решить с помощью цикла. Но в Python есть метод .split() . Именно его обычно используют для разделения строки на части. В качестве разделителя можно использовать любой символ: пробел, запятую, перенос строки ( \n ) и т.д.

На выходе мы получим список строк:

str = 'how are you' str.split(' ') # ['how', 'are', 'you'] 

Пробел как разделитель можно не указывать. Метод .split() будет использовать параметр по умолчанию:

str = 'how are you?' str.split() # ['how', 'are', 'you'] 

Иногда перед тем, как разделить строку, необходимо избавиться от лишних знаков препинания:

str = 'Hi, how are you?' str[:-1].replace(',', '').split() # ['Hi', 'how', 'are', 'you'] 

Как парсить строки с помощью Python?

Как с помощью Python парсить строки? Например, приходит инф с адресом «Киевская обл. , г. Киев, ул. Крещатик, дом 50, кв. 8» по факту этот адрес должен быть связан с ФИО клиента в БД. Но так как в БД залили не такой формат, то по поиску в БД не ищет ибо адрес может быть в другом порядке записан или без указания букв «кв», «дом» и тд.

  • Вопрос задан более трёх лет назад
  • 1330 просмотров

2 комментария

Средний 2 комментария

Уровень изложения на уровне.

Нужен пример входной строки и то, что нужно получить на выходе

A1K0

A1K0 @A1K0 Автор вопроса

Входной строки с бд? сори я пока не очень понимаю.
За изложение тоже сори, по той дже причине)
Коротко изложить, то нам нужно просто найти совпадения в БД и распарсить на нужные строки типа «область, город, улица. Дом. кв»

Решения вопроса 2

ScriptKiddo

ScriptKiddo @ScriptKiddo

Для начала вам нужно нормализовать адреса в базе. Сделать это можно, например, с помощью геокодера от Яндекса
/geocoder

Например, ищем «Москва, Тверская 6»

 < "response": < "GeoObjectCollection": < "metaDataProperty": < "GeocoderResponseMetaData": < "request": "Москва,Тверская 6", "results": "10", "found": "1" >>, "featureMember": [ < "GeoObject": < "metaDataProperty": < "GeocoderMetaData": < "precision": "exact", "text": "Россия, Москва, Тверская улица, 6с1", "kind": "house", "Address": < "country_code": "RU", "formatted": "Россия, Москва, Тверская улица, 6с1", "postal_code": "125009", "Components": [ < "kind": "country", "name": "Россия" >, < "kind": "province", "name": "Центральный федеральный округ" >, < "kind": "province", "name": "Москва" >, < "kind": "locality", "name": "Москва" >, < "kind": "street", "name": "Тверская улица" >, < "kind": "house", "name": "6с1" >] >, "AddressDetails": < "Country": < "AddressLine": "Россия, Москва, Тверская улица, 6с1", "CountryNameCode": "RU", "CountryName": "Россия", "AdministrativeArea": < "AdministrativeAreaName": "Москва", "Locality": < "LocalityName": "Москва", "Thoroughfare": < "ThoroughfareName": "Тверская улица", "Premise": < "PremiseNumber": "6с1", "PostalCode": < "PostalCodeNumber": "125009" >> > > > > > > >, "name": "Тверская улица, 6с1", "description": "Москва, Россия", "boundedBy": < "Envelope": < "lowerCorner": "37.607242 55.757926", "upperCorner": "37.615452 55.762556" >>, "Point": < "pos": "37.611347 55.760241" >> > ] > > >

После чего загружаете в базу в нужной схеме и ищете по нормализованным данным

Ответ по адресу из вопроса

 < "response": < "GeoObjectCollection": < "metaDataProperty": < "GeocoderResponseMetaData": < "request": "Киевская обл. , г. Киев, ул. Крещатик, дом 50, кв. 8", "results": "10", "found": "2" >>, "featureMember": [ < "GeoObject": < "metaDataProperty": < "GeocoderMetaData": < "precision": "exact", "text": "Украина, Киев, улица Крещатик, 50", "kind": "house", "Address": < "country_code": "UA", "formatted": "Украина, Киев, улица Крещатик, 50", "Components": [ < "kind": "country", "name": "Украина" >, < "kind": "province", "name": "Киев" >, < "kind": "locality", "name": "Киев" >, < "kind": "street", "name": "улица Крещатик" >, < "kind": "house", "name": "50" >] >, "AddressDetails": < "Country": < "AddressLine": "Украина, Киев, улица Крещатик, 50", "CountryNameCode": "UA", "CountryName": "Украина", "AdministrativeArea": < "AdministrativeAreaName": "Киев", "Locality": < "LocalityName": "Киев", "Thoroughfare": < "ThoroughfareName": "улица Крещатик", "Premise": < "PremiseNumber": "50" >> > > > > > >, "name": "улица Крещатик, 50", "description": "Киев, Украина", "boundedBy": < "Envelope": < "lowerCorner": "30.516022 50.440632", "upperCorner": "30.524232 50.445875" >>, "Point": < "pos": "30.520127 50.443254" >> >, < "GeoObject": < "metaDataProperty": < "GeocoderMetaData": < "precision": "other", "text": "Украина, Киевская область", "kind": "province", "Address": < "country_code": "UA", "formatted": "Украина, Киевская область", "Components": [ < "kind": "country", "name": "Украина" >, < "kind": "province", "name": "Киевская область" >] >, "AddressDetails": < "Country": < "AddressLine": "Украина, Киевская область", "CountryNameCode": "UA", "CountryName": "Украина", "AdministrativeArea": < "AdministrativeAreaName": "Киевская область" >> > > >, "name": "Киевская область", "description": "Украина", "boundedBy": < "Envelope": < "lowerCorner": "29.266411 49.179114", "upperCorner": "32.161466 51.554013" >>, "Point": < "pos": "30.456149 50.29807" >> > ] > > >

UPD: добавил ответ по адресу из вопроса.

Ответ написан более трёх лет назад
Нравится 3 2 комментария

vmamontov

ScriptKiddo, отличная мысль!
Если не ошибаюсь, геокодер отдаёт список совпадений. Можно брать первый результат в ответе. Но будет ли он правильным? ScriptKiddo, интересует твой опыт)
И кроме того, у геокодера есть ограничения по числу запросов. Хотя думаю их хватит, просто придётся парсить на протяжении нескольких дней.
Мне тоже интересна тема с обработкой адресов. Буду рад любым советам)

ScriptKiddo

ScriptKiddo @ScriptKiddo

Ограничение — 25K запросов в сутки, но если результаты будете использовать в коммерческой деятельности, то все равно придется использовать платную версию API

vmamontov

A1K0, добро пожаловать в дивный мир распарсивания адресов)
Это «кроличья нора».
В идеале адреса в базу данных должны писаться через справочники (КЛАДР, ФИАС): выбираешь из словаря город, потом улицу и т.д.
Если же у тебя адрес зашит в одну строку, в одно текстовое поле в БД, то пользователи могут писать адрес всевозможными способами. Часто имеют место ошибки в написании улиц, использование черточек, дефисов, дробей, запятых, точек с запятой. Если база содержит сотни тысяч записей, то выверить все ошибки будет очень долго и муторно.
Если адрес строго формализован, то проблем почти нет. Парсишь через разделитель.
Но перед этим советую посчитать число этих разделителей в каждой строке. Может оказаться так, что у тебя в одну запись попали два адреса (регистрации и фактического проживания).

list_address = ["Киевская обл. , г. Киев, ул. Крещатик, дом 10, кв. 8", "Киевская обл. , г. Киев, ул. Крещатик, 2, 12", "Киевская обл. , г. Киев, ул. Крещатик, д.20, кв.118", "Киевская обл. ; Киев; Крещатик; 50-8", "Киевская обл. , г. Киев, пл. Незалежности, д.12-а, строение 3, помещение 8, офис. 33",] for adr in list_address: # допустим разделитель запятая # и корректный адрес должен состоять из 5 частей region, city, street, house, flat = "", "", "", "", "", if adr.count(",") == 4: adr = adr.split(",") region = adr[0] city = adr[1] street = adr[2] house = adr[3] flat = adr[4] print(region, city, street, house, flat) # распарсятся три адреса и пяти: # Киевская обл. г. Киев ул. Крещатик дом 10 кв. 8 # Киевская обл. г. Киев ул. Крещатик 2 12 # Киевская обл. г. Киев ул. Крещатик д.20 кв.118

Ответ написан более трёх лет назад
Комментировать
Нравится 1 Комментировать
Ответы на вопрос 1

dimonchik2013

Dimonchik @dimonchik2013
non progredi est regredi

но не копипастом функции, а пониманием исходных данных и методов преобразования

кому тамита парсер понадобится, а кому — простое векторное расстояние названия улицы от массива улиц в базе

Как разделить строку на массив python

Привести строку к списку в пайтоне очень просто. Нужно воспользоваться конструктором list() — он превратит в список любой объект, поддерживающий итерацию, и строки в том числе.

s = 'foobaz' list(s) # ['f', 'o', 'o', 'b', 'a', 'z'] 

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *