Regex для извлечения в Python - PullRequest
0 голосов
/ 07 октября 2009

У меня есть такая строка:

"a word {{bla|123|456}} another {{bli|789|123}} some more text {{blu|789}} and more".

Я хотел бы получить это как вывод:

(("bla", 123, 456), ("bli", 789, 123), ("blu", 789))

Мне не удалось найти подходящее регулярное выражение для Python, чтобы достичь этого.

Ответы [ 7 ]

1 голос
/ 07 октября 2009
>>> re.findall(' {{(\w+)\|(\w+)(?:\|(\w+))?}} ', s)
[('bla', '123', '456'), ('bli', '789', '123'), ('blu', '789', '')]

если вам все еще нужен номер, вам нужно перебрать вывод и преобразовать его в целое число с помощью int.

1 голос
/ 07 октября 2009

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

regex = re.compile(r'\{\{(.*?)\|(.*?)(?:\|(.*?))?\}\}')
regex.findall(line)

Для примера это дает:

[('bla', '123', '456'), ('bli', '789', '123'), ('blu', '789', '')]

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

0 голосов
/ 07 октября 2009

Пипарсинг излишним для этого? Возможно, но без особых страданий, действительно доставляет желаемый результат без чёртов обратной косой черты, чтобы избежать символов '{', '|' или '}'. Кроме того, нет необходимости в преобразовании целых чисел и тому подобном после разбора - действия разбора позаботятся о подобных вещах во время разбора.

from pyparsing import Word, Suppress, alphas, alphanums, nums, delimitedList

LBRACE,RBRACE,VERT = map(Suppress,"{}|")
word = Word(alphas,alphanums)
integer = Word(nums)
integer.setParseAction(lambda t: int(t[0]))

patt = (LBRACE*2 + delimitedList(word|integer, VERT) + RBRACE*2)
patt.setParseAction(lambda toks:tuple(toks.asList()))


s = "a word {{bla|123|456}} another {{bli|789|123}} some more text {{blu|789}} and more"

print tuple(p[0] for p in patt.searchString(s))

Печать:

(('bla', 123, 456), ('bli', 789, 123), ('blu', 789))
0 голосов
/ 07 октября 2009

Предполагая, что ваш фактический формат {{[a-z]+|[0-9]+|[0-9]+}}, вот полная программа с преобразованием в целые числа.

import re

s = "a word {{bla|123|456}} another {{bli|789|123}} some more text {{blu|789}} and more"
result = []

for match in re.finditer('{{.*?}}', s):

   # Split on pipe (|) and filter out non-alphanumerics
   parts = [filter(str.isalnum, part) for part in match.group().split('|')]

   # Convert to int when possible
   for index, part in enumerate(parts):      
      try:
         parts[index] = int(part)
      except ValueError:
         pass

   result.append(tuple(parts))
0 голосов
/ 07 октября 2009

Возможно, мы сможем придумать и сделать все в одном сложном регулярном выражении, но в этом и заключается безумие. Давайте сделаем одно регулярное выражение, которое захватит группы, а затем разделит группы на части. Мы можем использовать регулярное выражение для разделения групп, но мы можем просто использовать str.split (), поэтому давайте сделаем это.

import re
pat_group = re.compile("{{([^}]*)}}")
def mixed_tuple(iterable):
    lst = []
    for x in iterable:
        try:
            lst.append(int(x))
        except ValueError:
            lst.append(x)
    return tuple(lst)

s = "a word {{bla|123|456}} another {{bli|789|123}} some more text {{blu|789}} and more"

lst_groups = re.findall(pat_group, s)
lst = [mixed_tuple(x.split("|")) for x in lst_groups]

В pat_group "{{" просто совпадает с литералом "{{". "(" начинает группу. "[^}]" - это класс символов, который соответствует любому символу, кроме «}», а «*» позволяет ему соответствовать нулю или более таких символов. }} "соответствует буквенным символам. Таким образом, мы сопоставляем шаблоны "{{...}}" и можем извлечь все между фигурными скобками как группу.

re.findall () возвращает список групп, соответствующих шаблону.

Наконец, понимание списка разбивает каждую строку и возвращает результат в виде кортежа.

0 голосов
/ 07 октября 2009

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

import re
map(lambda s: s.split("|"), re.findall(r"\{\{([^}]*)\}\}", s))

Чтобы получить преобразованные числа, сделайте следующее:

toint = lambda x: int(x) if x.isdigit() else x
[map(toint, p.split("|")) for p in re.findall(r"\{\{([^}]*)\}\}", s)]
0 голосов
/ 07 октября 2009
[re.split('\|', i) for i in re.findall("{{(.*?)}}", str)]

Возвращает:

[['bla', '123', '456'], ['bli', '789', '123'], ['blu', '789']]

Этот метод работает независимо от количества элементов в блоках {{}}.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...