используйте регулярное выражение для разделения списка серийных номеров на несколько списков с совпадающим префиксом

Вопрос исходит от Как разделить список серийных номеров на несколько списков с совпадающим префиксом? о переполнении стека.

Вход:

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 ответа
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)
      

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

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