Собесов

Совкомбанк Страхование: VBA / Python — извлечь город из адреса

PythonПарсинг текстаЛёгкаяJunior

Условие

Даны два листа Excel:

  • Города: список (Москва, Санкт-Петербург, Казань, Владивосток, Новосибирск).
  • Адреса: строки вида г. Москва, ул. Пятницкая, дом 33, г новосибирск, улица дорожная, дом 44, и т. д.

Нужно макросом VBA (или Python) для каждого адреса в соседнюю ячейку проставить найденный город из списка, иначе — пусто.

Решение

Python (pandas)

import pandas as pd, re
 
cities = pd.read_excel('addr.xlsx', sheet_name='Города').Город.tolist()
addr   = pd.read_excel('addr.xlsx', sheet_name='Адреса')
 
def find_city(line, cities):
    if not isinstance(line, str):
        return None
    line_low = line.lower()
    # Сортировка по длине: Санкт-Петербург ставим первым, чтобы не зацепиться за Петер-чтото
    for c in sorted(cities, key=len, reverse=True):
        if c.lower() in line_low:
            return c
    return None
 
addr['Город'] = addr.Адреса.apply(lambda s: find_city(s, cities))
addr.to_excel('out.xlsx', index=False)

VBA-аналог

Sub FindCities()
    Dim cities As Variant
    cities = Array("Москва", "Санкт-Петербург", "Казань", "Владивосток", "Новосибирск")
 
    Dim ws As Worksheet, lastRow As Long, i As Long, j As Long, addr As String
    Set ws = Sheets("Адреса")
    lastRow = ws.Cells(Rows.Count, 1).End(xlUp).Row
 
    For i = 2 To lastRow
        addr = LCase(ws.Cells(i, 1).Value)
        For j = LBound(cities) To UBound(cities)
            If InStr(1, addr, LCase(cities(j))) > 0 Then
                ws.Cells(i, 2).Value = cities(j)
                Exit For
            End If
        Next j
    Next i
End Sub

Подводные камни

  1. Регистр в исходных адресах разный (г.казань, г Новосибирск) — обязательно LCase / lower().
  2. «Тула» / «Петрозаводск» не в списке — должно остаться пусто.
  3. Порядок поиска: «Санкт-Петербург» нужно проверять до «Петербург» (если он бы был в списке) и до коротких имён, иначе ложные срабатывания.
  4. Адреса могут содержать сокращения (спб, мск, н.новгород); в задании этого нет, но пригодится словарь алиасов.
  5. Скорость: для тысяч строк цикл медленный — лучше векторно (str.contains с |-объединением).

Эталонный ответ

Python: find_city с поиском подстроки в lower() адреса в порядке убывания длины. VBA: вложенный цикл For + InStr + LCase.

Хочешь увидеть разбор?

Зарегистрируйся бесплатно — откроется развёрнутое решение этой задачи и ещё 4 на выбор.

Зарегистрироваться и увидеть разбор
Уже есть аккаунт? Войти