Регулярное выражение Python для выбора пробелов между круглыми скобками [duplicate]

В моем случае у нас есть временные ряды с разных устройств, но некоторые устройства не могли отправить какое-либо значение в течение некоторого периода времени. Таким образом, мы должны создавать значения NA для каждого устройства и период времени, а затем делать fillna.

df = pd.DataFrame([["device1", 1, 'first val of device1'], ["device2", 2, 'first val of device2'], ["device3", 3, 'first val of device3']])
df.pivot(index=1, columns=0, values=2).fillna(method='ffill').unstack().reset_index(name='value')

Результат:

        0   1   value
0   device1     1   first val of device1
1   device1     2   first val of device1
2   device1     3   first val of device1
3   device2     1   None
4   device2     2   first val of device2
5   device2     3   first val of device2
6   device3     1   None
7   device3     2   None
8   device3     3   first val of device3
22
задан kender 30 October 2009 в 09:11
поделиться

10 ответов

Один из способов сделать это - использовать 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 или более не-закрытых парен, а затем близкий парен

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

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

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

Если вам нужно иметь дело с вложением, лучшим выбором будет разбиение строки на парсеры, запятые и все остальное (в основном, токенизация - это часть все равно может выполняться с помощью регулярных выражений), а затем пройдите через те маркеры, которые снова собирают поля, отслеживая уровень вашего гнездования, когда вы идете (это отслеживание уровня вложенности - это то, что регулярные выражения не могут делать самостоятельно).

19
ответ дан Laurence Gonsalves 22 August 2018 в 06:37
поделиться
  • 1
    Вы можете сразу разбить на поля путем сопоставления записей вместо разделителей: [(m.group («имя»), m.group («роль»)) для m в re.findall («? & Lt; name & gt; ; & Thetas;) & le;) (& thetas; (& lt; роль & gt; [^)] +)) (, \ s * | $)) ", x)] – Alexander Lebedev 30 October 2009 в 09:38
  • 2
    +1 для решения токена, если он ему нужен. Поп-ап и выходите из стека, когда вы идете вверх и вниз ... классический способ сделать это. – Paul McMillan 30 October 2009 в 09:39
  • 3
    каждый раз, когда я вижу регулярное выражение, которое полезно, как этот, я начинаю задаваться вопросом - должны ли они быть читаемыми человеком? Или это только я ... кто не видит это с первого взгляда? – kender 30 October 2009 в 10:21
  • 4
    Отличный ответ. Спасибо, Лоуренс! Как я могу подойти к этой проблеме, если я хочу сделать то же самое, но not включает содержимое в круглых скобках на выходе? – Amelio Vazquez-Reina 16 November 2013 в 22:48
  • 5
    @ user815423426 Подход, который я, вероятно, использовал бы в этом случае, состоял бы в том, чтобы сделать второй проход по результирующему списку и удалить parens. например: что-то вроде r = [re.sub(r'\([^)]*\)', '', s) for s in r]. Если вам нужен более подробный ответ, вероятно, вы должны задать отдельный вопрос. – Laurence Gonsalves 18 November 2013 в 20:53
s = re.split(r',\s*(?=[^)]*(?:\(|$))', x) 

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

5
ответ дан Alan Moore 22 August 2018 в 06:37
поделиться

Этот пост мне очень помог. Я искал разбиение строки запятыми, расположенными вне кавычек. Я использовал это как стартер. Моя последняя строка кода была regEx = re.compile(r'(?:[^,"]|"[^"]*")+'). Это сделал трюк. Спасибо тонну.

1
ответ дан Alessandro 22 August 2018 в 06:37
поделиться

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

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

HTH

0
ответ дан Anand Shah 22 August 2018 в 06:37
поделиться

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

Используйте функцию sub модуля re с функцией в качестве аргумента замены. Функция отслеживает открытие и закрытие парсеров, кронштейнов и брекетов, а также одиночные и двойные кавычки и выполняет замену только за пределами таких заключенных в скобки и подкатегорий. Затем вы можете заменить запятые без кавычек на другой символ, который, как вы уверены, не отображается в строке (я использую код ASCII / Unicode group-separator: 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

Если у вас нет nonlocal в вашей версии Python, просто измените его на global и определите level и 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
ответ дан Don O'Donnell 22 August 2018 в 06:37
поделиться

split by ")"

>>> 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
ответ дан ghostdog74 22 August 2018 в 06:37
поделиться

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

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
ответ дан jfs 22 August 2018 в 06:37
поделиться
  • 1
    Человеческое читаемое регулярное выражение - разве это не оксюморон? – Amarghosh 5 November 2009 в 14:33

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

Я думаю, что должен работать простой сканер символов с состоянием «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
ответ дан Michał Niklas 22 August 2018 в 06:37
поделиться

Ни один из приведенных выше ответов не является правильным, если в ваших данных есть какие-либо ошибки или шум.

Легко придумать хорошее решение, если вы знаете, что данные правильны каждый раз. Но что произойдет, если есть ошибки форматирования? Что вы хотите добиться?

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

Все вышеупомянутые решения будут вызывать больше или меньше мусора и не сообщать об этом вам.

Если бы это зависело от меня, я бы начал с довольно строгим ограничением на то, что «правильные» данные были: никаких скобок вложенности, не совпадающих круглых скобок и без пустых сегментов до, между или после комментариев - подтвердите, когда я пошел, а затем поднимите исключение, если я не смог проверить.

-1
ответ дан Tom Swirly 22 August 2018 в 06:37
поделиться
  • 1
    Мы должны предположить, что этот вопрос содержит всю информацию, необходимую нам для ответа. Таким образом, мы предполагаем, что вход уже проверен и что формат был описан полностью (например, нет вложенных круглых скобок). Если какое-либо из этих предположений окажется неправильным, можно надеяться, что ОП научится задавать лучшие вопросы в будущем. ;) – Alan Moore 1 November 2009 в 04:01

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

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

5
ответ дан Wogan 22 August 2018 в 06:37
поделиться
Другие вопросы по тегам:

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