Вопрос исходит от Как разделить список серийных номеров на несколько списков с совпадающим префиксом? о переполнении стека.
Вход:
sn = ['bike-001', 'bike-002', 'car/001', 'bus/for/001', 'car/002', 'bus/for/002']
Предполагаемый результат:
# string with same prefix will be in the same list, e.g.: sn1 = ['bike-001', 'bike-002'] sn2 = ['car/001', 'car/002'] sn3 = ['bus/for/001', 'bus/for/002']
В исходной ветке уже был блестящий ответ с использованием .startswith(<sub_str>)
, однако я все еще хочу использовать regex
чтобы решить вопрос.
Вот что я пробовал: я использую re.sub()
получить префикс и re.search()
чтобы получить трехзначный серийный номер. Я хотел бы знать, есть ли способ лучше (например, одноразовый regex
функция), чтобы получить решение.
import re
sn = ['bike-001', 'bike-002', 'car/001', 'bus/for/001', 'car/002', 'bus/for/002']
sn_dict = {}
for item in sn:
category = re.sub(r'd{3}', "", item)
number = re.search(r'd{3}', item).group()
if category not in sn_dict.keys():
sn_dict[category] = []
sn_dict[category].append(category + number)
После запуска скрипта у нас будет следующее sn_dict
:
{
'bike-': ['bike-001', 'bike-002'],
'car/': ['car/001', 'car/002'],
'bus/for/': ['bus/for/001', 'bus/for/002']
}
3 ответа
Вы можете сделать это с помощью re.findall
. Вместо перебора каждой строки вы можете объединить все серийные номера в одну строку и использовать regex
чтобы найти все совпадения (эта реализация предполагает, что в серийном номере нет пробелов).
import re
string_list = ['bike-001', 'bike-002', 'car/001', 'bus/for/001', 'car/002', 'bus/for/002']
string = ' '.join(string_list)
matches = re.findall(r"([^0-9])", string)
numbers = re.findall(r"([0-9]{3})", string)
prefixes="".join(c for c in matches).split()
result_dict = {}
for prefix, number in zip(prefixes, numbers):
if prefix not in result_dict.keys():
result_dict[prefix] = []
result_dict[prefix].append(prefix + number)
Первый re.findall
ищет любую строку, которая нет число. Вторая находка любой последовательность трех чисел. Следующая строка объединяет символы в matches
, и поскольку мы обозначили, что мы отделили каждый серийный номер символом ' '
, мы можем разделить, используя одно и то же значение. Затем мы используем тот же код, что и в вашем вопросе, для заполнения словаря результатов.
С точки зрения того, что мы принимаем, возможно, стоит привязать цифровую строку к концу item
с $
.
Код, похоже, переопределяет довольно много itertools.groupby
. Предполагая, что нас не волнует порядок, мы могли бы легко переписать, чтобы построить это, отсортировав ввод и передав подходящий key
функция.
Или напишите более общий split_to()
функция, которая принимает key
функционируют аналогично groupby
, поэтому мы можем отделить общий механизм от конкретного экземпляра, который у нас есть.
В качестве альтернативного решения вы можете избежать конкатенации и рекомбинации строк и вместо этого просто сопоставить с префиксом и добавить в dict прямо оттуда.
import re
string_list = ['bike-001', 'bike-002', 'car/001', 'bus/for/001', 'car/002', 'bus/for/002']
result_dic = {}
for item in string_list:
prefix = re.match("([^0-9]+)", item).group()
if prefix not in result_dic:
result_dic[prefix] = []
result_dic[prefix].append(item)