Как разделить строку запятыми, расположенными за пределами круглой скобки?

  1. Нет. И я подозреваю, что большинство людей не доверяют этому грубому механизму

  2. Совсем немного, особенно если у вас уже есть стол.

  3. Взгляните на это, например: http://forums.asp.net/t/1250726.aspx

22
задан kender 30 October 2009 в 08:11
поделиться

9 ответов

Один из способов сделать это - использовать findall с регулярным выражением, которое жадно сопоставляет вещи, которые могут находиться между разделителями. например:

>>> s = "Wilbur Smith (Billy, son of John), Eddie Murphy (John), Elvis Presley, Jane Doe (Jane Doe)"
>>> r = re.compile(r'(?:[^,(]|\([^)]*\))+')
>>> r.findall(s)
['Wilbur Smith (Billy, son of John)', ' Eddie Murphy (John)', ' Elvis Presley', ' Jane Doe (Jane Doe)']

Регулярное выражение, приведенное выше, соответствует одному или нескольким:

  • символы без запятой, без закрывающих скобок
  • строки, которые начинаются с открытого парного знака, содержат 0 или более закрытых пар, а затем close paren

Одна из особенностей этого подхода состоит в том, что смежные разделители рассматриваются как один разделитель. То есть вы не увидите пустую строку. Это может быть ошибкой или функцией в зависимости от вашего варианта использования.

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

"Wilbur Smith (son of John (Johnny, son of James), aka Billy), Eddie Murphy (John)"

Если вам нужно иметь дело с вложением, лучше всего будет разбить строку на скобки, запятые и

19
ответ дан 29 November 2019 в 05:10
поделиться

Попытка создать удобочитаемое регулярное выражение:

import re

regex = re.compile(r"""
    # name starts and ends on word boundary
    # no '(' or commas in the name
    (?P<name>\b[^(,]+\b)
    \s*
    # everything inside parentheses is a role
    (?:\(
      (?P<role>[^)]+)
    \))? # role is optional
    """, re.VERBOSE)

s = ("Wilbur Smith (Billy, son of John), Eddie Murphy (John), Elvis Presley,"
     "Jane Doe (Jane Doe)")
print re.findall(regex, s)

Вывод:

[('Wilbur Smith', 'Billy, son of John'), ('Eddie Murphy', 'John'), 
 ('Elvis Presley', ''), ('Jane Doe', 'Jane Doe')]
2
ответ дан 29 November 2019 в 05:10
поделиться

разделить на ")"

>>> s="Wilbur Smith (Billy, son of John), Eddie Murphy (John), Elvis Presley, Jane Doe (Jane Doe)"
>>> s.split(")")
['Wilbur Smith (Billy, son of John', ', Eddie Murphy (John', ', Elvis Presley, Jane Doe (Jane Doe', '']
>>> for i in s.split(")"):
...   print i.split("(")
...
['Wilbur Smith ', 'Billy, son of John']
[', Eddie Murphy ', 'John']
[', Elvis Presley, Jane Doe ', 'Jane Doe']
['']

, вы можете выполнить дополнительную проверку, чтобы получить те имена, которые не идут с ().

0
ответ дан 29 November 2019 в 05:10
поделиться
s = re.split(r',\s*(?=[^)]*(?:\(|$))', x) 

Предварительный просмотр соответствует всем, вплоть до следующая открывающая скобка или до конца строки, iff между ними нет закрывающих скобок. Это гарантирует, что запятая не окажется внутри скобок.

5
ответ дан 29 November 2019 в 05:10
поделиться

None of the answers above are correct if there are any errors or noise in your data.

It's easy to come up with a good solution if you know the data is right every time. But what happens if there are formatting errors? What do you want to have happen?

Suppose there are nesting parentheses? Suppose there are unmatched parentheses? Suppose the string ends with or begins with a comma, or has two in a row?

All of the above solutions will produce more or less garbage and not report it to you.

Were it up to me, I'd start with a pretty strict restriction on what "correct" data was - no nesting parentheses, no unmatched parentheses, and no empty segments before, between or after comments - validate as I went, and then raise an exception if I wasn't able to validate.

-1
ответ дан 29 November 2019 в 05:10
поделиться

Я думаю, что лучший способ приблизиться к этому - использовать встроенные функции Python. в модуле csv .

Поскольку модуль csv только позволяет односимвольный quotechar , вам нужно будет заменить входные данные для преобразования () на что-то вроде | или ". Затем убедитесь, что вы используете подходящий диалект, и вперед.

5
ответ дан 29 November 2019 в 05:10
поделиться

Мой ответ не будет использовать регулярное выражение.

Я думаю, что простой сканер символов с состоянием « in_actor_name » должен работать. Помните, что в этом состоянии состояние « in_actor_name » завершается символом «)» или запятой.

Моя попытка:

s = 'Wilbur Smith (Billy, son of John), Eddie Murphy (John), Elvis Presley, Jane Doe (Jane Doe)'

in_actor_name = 1
role = ''
name = ''
for c in s:
    if c == ')' or (c == ',' and in_actor_name):
        in_actor_name = 1
        name = name.strip()
        if name:
            print "%s: %s" % (name, role)
        name = ''
        role = ''
    elif c == '(':
        in_actor_name = 0
    else:
        if in_actor_name:
            name += c
        else:
            role += c
if name:
    print "%s: %s" % (name, role)

Вывод:

Wilbur Smith: Billy, son of John
Eddie Murphy: John
Elvis Presley: 
Jane Doe: Jane Doe
1
ответ дан 29 November 2019 в 05:10
поделиться

Я, конечно, согласен с @Wogan выше, что использование CSV moudle - хороший подход. При этом, если вы все еще хотите попробовать решение с регулярными выражениями, попробуйте, но вам придется адаптировать его к диалекту Python

string.split(/,(?=(?:[^\"]*\"[^\"]*\")*(?![^\"]*\"))/)

HTH

0
ответ дан 29 November 2019 в 05:10
поделиться

Вот общий прием, который я использовал в прошлом для таких случаев:

Используйте функцию sub модуля re с функция как аргумент замены. Функция отслеживает открывающие и закрывающие скобки, скобки и фигурные скобки, а также одинарные и двойные кавычки и выполняет замену только за пределами таких заключенных в квадратные скобки и заключенных в кавычки подстрок. Затем вы можете заменить запятые без скобок / кавычек другим символом, который, как вы уверены, не появляется в строке (я использую разделитель групп ASCII / Unicode: код chr (29)), а затем введите простую строку. разделить на этого персонажа. Вот код:

import re
def srchrepl(srch, repl, string):
    """Replace non-bracketed/quoted occurrences of srch with repl in string"""

    resrchrepl = re.compile(r"""(?P<lbrkt>[([{])|(?P<quote>['"])|(?P<sep>["""
                            + srch + """])|(?P<rbrkt>[)\]}])""")
    return resrchrepl.sub(_subfact(repl), string)

def _subfact(repl):
    """Replacement function factory for regex sub method in srchrepl."""
    level = 0
    qtflags = 0
    def subf(mo):
        nonlocal level, qtflags
        sepfound = mo.group('sep')
        if  sepfound:
            if level == 0 and qtflags == 0:
                return repl
            else:
                return mo.group(0)
        elif mo.group('lbrkt'):
            level += 1
            return mo.group(0)
        elif mo.group('quote') == "'":
            qtflags ^= 1            # toggle bit 1
            return "'"
        elif mo.group('quote') == '"':
            qtflags ^= 2            # toggle bit 2
            return '"'
        elif mo.group('rbrkt'):
            level -= 1
            return mo.group(0)
    return subf

Если у вас нет нелокального в вашей версии Python, просто измените его на global и определите уровень и qtflags на уровне модуля.

Вот как это используется:

>>> GRPSEP = chr(29)
>>> string = "Wilbur Smith (Billy, son of John), Eddie Murphy (John), Elvis Presley, Jane Doe (Jane Doe)"
>>> lst = srchrepl(',', GRPSEP, string).split(GRPSEP)
>>> lst
['Wilbur Smith (Billy, son of John)', ' Eddie Murphy (John)', ' Elvis Presley', ' Jane Doe (Jane Doe)']
1
ответ дан 29 November 2019 в 05:10
поделиться
Другие вопросы по тегам:

Похожие вопросы: