Python Regex для разбора строки и возврата кортежа - PullRequest
12 голосов
/ 07 июня 2011

Мне дали несколько строк для работы. Каждый представляет набор данных и состоит из имени набора данных и связанной статистики. Все они имеют следующую форму:

s= "| 'TOMATOES_PICKED'                                  |       914 |       1397 |"

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

def extract_data2(s):
    import re
    name=re.search('\'(.*?)\'',s).group(1)
    n1=re.search('\|(.*)\|',s)
    return(name,n1,)

Итак, я немного почитал регулярные выражения и выяснил, как вернуть имя. Для каждой из строк, с которыми я работаю, имя набора данных ограничено символом «», поэтому я нашел это имя. Эта часть отлично работает. Моя проблема с получением номеров. Сейчас я думаю о том, чтобы попытаться сопоставить шаблон, которому предшествует вертикальная черта ('|'), затем что-нибудь (вот почему я использовал. *), А затем еще одну вертикальную черту, чтобы попытаться получить первый номер Кто-нибудь знает, как я могу сделать это в Python? То, что я пробовал в приведенном выше коде для первого числа, возвращает в основном всю строку в качестве моего вывода, тогда как я хочу получить только число. -Я очень новичок в программировании, поэтому я прошу прощения, если этот вопрос кажется рудиментарным, но я довольно усердно читал и искал ответы, которые близки к моему случаю, но безуспешно. Я ценю любую помощь. Идея в том, что он сможет:

return(name,n1,n2)

так, что когда пользователь вводит строку, он может просто проанализировать строку и вернуть важную информацию. Я заметил, что в моих попытках получить числа так далеко, что он вернет число в виде строки. Есть ли способ вернуть n1 или n2 как просто число? Обратите внимание, что для некоторых строк n1 и n2 могут быть целыми числами или иметь десятичную дробь.

Ответы [ 6 ]

25 голосов
/ 07 июня 2011

Я бы использовал одно регулярное выражение для сопоставления всей строки с нужными частями в именованных группах ((?P<name>exampl*e)).

import re
def extract_data2(s):
    pattern = re.compile(r"""\|\s*                 # opening bar and whitespace
                             '(?P<name>.*?)'       # quoted name
                             \s*\|\s*(?P<n1>.*?)   # whitespace, next bar, n1
                             \s*\|\s*(?P<n2>.*?)   # whitespace, next bar, n2
                             \s*\|""", re.VERBOSE)
    match = pattern.match(s)

    name = match.group("name")
    n1 = float(match.group("n1"))
    n2 = float(match.group("n2"))

    return (name, n1, n2)

Чтобы преобразовать n1 и n2 из строк в числа, я использую функцию float. (Если бы они были только целыми числами, я бы использовал функцию int.)

Я использовал флаг re.VERBOSE и необработанные многострочные строки (r"""..."""), чтобы облегчить чтение регулярного выражения.

3 голосов
/ 07 июня 2011

Попробуйте использовать сплит.

s= "| 'TOMATOES_PICKED'                                  |       914 |       1397 |"
print map(lambda x:x.strip("' "),s.split('|'))[1:-1]
  • Разделить: преобразовать вашу строку в список строк
  • лямбда-функция: удаляет пробелы и '
  • Селектор: брать только ожидаемые детали
3 голосов
/ 07 июня 2011

Использование регулярного выражения:

#! /usr/bin/env python

import re

tests = [
"| 'TOMATOES_PICKED'                                  |       914 |       1397 |",
"| 'TOMATOES_FLICKED'                                 |     32914 |       1123 |",
"| 'TOMATOES_RIGGED'                                  |        14 |       1343 |",
"| 'TOMATOES_PICKELED'                                |         4 |         23 |"]

def parse (s):
    mo = re.match ("\\|\s*'([^']*)'\s*\\|\s*(\d*)\s*\\|\s*(\d*)\s*\\|", s)
    if mo: return mo.groups ()

for test in tests: print parse (test)
2 голосов
/ 07 июня 2011

Не уверен, что я правильно вас понял, но попробуйте это:

import re

print re.findall(r'\b\w+\b', yourtext)
1 голос
/ 07 июня 2011

Я бы согласился с другими авторами, которые сказали, что в ваших строках используется метод split (). Если заданная вами строка,

>> s = "| 'TOMATOES_PICKED'                          |       914 |       1397 |"

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

>> s_new = s.split()
>> s_new
['|', "'TOMATOES_PICKED'", '|', '914', '|', '1397', '|']

Конечно, у вас также есть "|" характер, но это кажется последовательным в вашем наборе данных, так что это не большая проблема для решения. Просто игнорируйте их.

0 голосов
/ 07 июня 2011

С помощью pyparsing вы можете заставить синтаксический анализатор создать для вас dict-подобную структуру, используя значения первого столбца в качестве ключей и последующие значения в виде массива значений для этого ключа:

>>> from pyparsing import *
>>> s = "| 'TOMATOES_PICKED'                                  |       914 |       1397 |"
>>> VERT = Suppress('|')
>>> title = quotedString.setParseAction(removeQuotes)
>>> integer = Word(nums).setParseAction(lambda tokens:int(tokens[0]))
>>> entry = Group(VERT + title + VERT + integer + VERT + integer + VERT)
>>> entries = Dict(OneOrMore(entry))
>>> data = entries.parseString(s)
>>> data.keys()
['TOMATOES_PICKED']
>>> data['TOMATOES_PICKED']
([914, 1397], {})
>>> data['TOMATOES_PICKED'].asList()
[914, 1397]
>>> data['TOMATOES_PICKED'][0]
914
>>> data['TOMATOES_PICKED'][1]
1397

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

...