Условие
Даны два листа 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Подводные камни
- Регистр в исходных адресах разный (
г.казань,г Новосибирск) — обязательноLCase/lower(). - «Тула» / «Петрозаводск» не в списке — должно остаться пусто.
- Порядок поиска: «Санкт-Петербург» нужно проверять до «Петербург» (если он бы был в списке) и до коротких имён, иначе ложные срабатывания.
- Адреса могут содержать сокращения (
спб,мск,н.новгород); в задании этого нет, но пригодится словарь алиасов. - Скорость: для тысяч строк цикл медленный — лучше векторно (
str.containsс|-объединением).
Эталонный ответ
Python: find_city с поиском подстроки в lower() адреса в порядке убывания длины. VBA: вложенный цикл For + InStr + LCase.