Существует ли регулярное выражение для рекурсивного изменения списка и изменения его элементов в python3? - PullRequest
0 голосов
/ 02 февраля 2020

У меня есть список строк в следующем формате:

["6,7",
"6-8",
"10,12",
"15-18"]

Мне нужно разбить строки на отдельные элементы. Если , есть, мне просто нужно разделить элемент. Если - есть, мне нужно сгенерировать диапазон чисел, чтобы включить числа между ними.

Пример: '6,7' разбивается на ['6','7'], а '6-8' изменяется на ['6','7','8']

Я написал эту функцию, которая прекрасно работает для этого:

def process_nums(verse_nums_):
     if ',' in verse_nums_:
         verse_nums = [i for i in map(str.strip,verse_nums_.split(','))]
     elif '-' in verse_nums_:
         beg_end = [int(i) for i in map(str.strip,verse_nums_.split('-'))]
         verse_nums = [i for i in range(beg_end[0],beg_end[1]+1)]
     else:
         verse_nums = [verse_nums_]
     return verse_nums

Однако я застрял со строкой: '6-8,10'. Это должно быть изменено на ['6','7','8','10']. Я могу сделать начальное разделение, чтобы получить ['6-8','10'].

Я написал несколько раундов о коде, который нужно пройти:

verse_nums = process_nums('6-8,10')

        for x in verse_nums:
            if '-' in x:
                verse_nums.extend(process_nums(x))
                verse_nums.pop(verse_nums.index(x))
        verse_nums = [int(i) for i in verse_nums].sort()

Есть ли более элегантный способ сделать это?

Примечание: я не уверен, как правильно сформулировать вопрос в заголовке. Пожалуйста, не стесняйтесь изменять.

Ответы [ 4 ]

3 голосов
/ 02 февраля 2020

Я думаю, вы довольно близки. Не требуется регулярное выражение. Я всегда делю запятую, а затем новые части либо содержат диапазон, либо являются отдельными элементами.

def process_nums(nums):
  parts = nums.split(',')
  for part in parts:
    if '-' in part:
      a, b = part.split('-')
      yield from (str(i) for i in range(int(a), int(b)+1))
    else:
      yield part

print(list(process_nums('6-8,10')))
1 голос
/ 02 февраля 2020

попробуйте это:

mylist = ["6,7","6-8","10,12","15-18"]
new_list = []



for i in mylist :
    if ',' in i :
        splited = i.split(',')
        new_list.append(splited[0])
        new_list.append(splited[1])
    elif '-' in i :
        splited = i.split('-')
        x = range(int(splited[0]),int(splited[1])+1)
        for y in x :
            new_list.append(str(y))

print(new_list)

вывод:

['6', '7', '6', '7', '8', '10', '12', '15', '16', '17', '18']
1 голос
/ 02 февраля 2020

Регулярное выражение IMO лучше, потому что str.split может не обнаружить недопустимый ввод, такой как: ", -, - 2"

import re
from typing import List


def process(numbers: List[str]) -> List[str]:
    output = []
    for no_idea_what_this_is in numbers:
        for value in no_idea_what_this_is.split(","):
            match = re.fullmatch(r"(\d+)-(\d+)", value)
            if match:
                start = int(match.group(1))
                stop = int(match.group(2)) + 1
                output.extend([str(i) for i in range(start, stop)])
            elif re.fullmatch("\d+", value):
                output.append(value)
            else:
                raise ValueError(f"Unable to parse {value}")
    return output


print(process(["4-8,10"]))
# ['4', '5', '6', '7', '8', '10']

1 голос
/ 02 февраля 2020

Мы можем сделать небольшой мод для кодирования из ОБЩИЙ СПИСОК НОМЕРОВ ИЗ ГИФЕНИРОВАННОЙ И КОМПАКТНОЙ СТРОКИ, КАК РАЗДЕЛИТЬ, КАК "1-5,25-30,4,5" (PYTHON RECIPE)

Преимущество этого подхода (сверх опубликованного) заключается в том, что его способность обрабатывать более сложные диапазоны с перекрытиями, такими как:

Для:

'2,3,4-8,2-5,9'

Производит

['2', '3', '4', '5', '6', '7', '8', '9'] 

В то время как принятое решение выдает

['2', ' 3', '4', '5', '6', '7', '8', '2', '3', '4', '5', ' 9']

С повторяющимися индексами

def hyphen_range(s):
    """ Takes a range in form of "a-b" and generate a list of numbers between a and b inclusive.
    Also accepts comma separated ranges like "a-b,c-d,f" will build a list which will include
    Numbers from a to b, a to d and f"""
    s= "".join(s.split())#removes white space
    r= set()
    for x in s.split(','):
        t=x.split('-')
        if len(t) not in [1,2]: raise SyntaxError("hash_range is given its arguement as "+s+" which seems not correctly formated.")
        r.add(int(t[0])) if len(t)==1 else r.update(set(range(int(t[0]),int(t[1])+1)))
    l=list(r)
    l.sort()
    return list(map(str, l))  # added string conversion

# Test shows handling of overlapping ranges and commas in pattern
# i.e. '2, 3, 4-8, 2-5, 9'
for x in ["6,7", "6-8", "10,12", "15-18", '6-8,10', '2, 3, 4-8, 2-5, 9']:
  print(f"'{x}' -> {hyphen_range(x)}")

Выход

'6,7' -> ['6', '7']
'6-8' -> ['6', '7', '8']
'10,12' -> ['10', '12']
'15-18' -> ['15', '16', '17', '18']'6-8,10' -> ['6', '7', '8', '10']
'6-8,10' -> ['6', '7', '8', '10']
'2, 3, 4-8, 2-5, 9' -> ['2', '3', '4', '5', '6', '7', '8', '9']

Генератор Версия

def hyphen_range_generator(s):
    """ yield each integer from a complex range string like "1-9,12, 15-20,23"

    >>> list(hyphen_range('1-9,12, 15-20,23'))
    [1, 2, 3, 4, 5, 6, 7, 8, 9, 12, 15, 16, 17, 18, 19, 20, 23]

    >>> list(hyphen_range('1-9,12, 15-20,2-3-4'))
    Traceback (most recent call last):
        ...
    ValueError: format error in 2-3-4
    """
    for x in s.split(','):
        elem = x.split('-')
        if len(elem) == 1: # a number
            yield int(elem[0])
        elif len(elem) == 2: # a range inclusive
            start, end = map(int, elem)
            for i in range(start, end+1):
                yield str(i)  # only mod to posted software
        else: # more than one hyphen
            raise ValueError('format error in %s' % x)

# Need to use list(...) to see output since using generator
for x in ["6,7", "6-8", "10,12", "15-18", '6-8,10', '2, 3, 4-8, 2-5, 9']:
  print(f"'{x}' -> {list(hyphen_range_generator(x))}")

Выход

Same as the non-generator version above
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...