Как извлечь несколько строк с помощью регулярных выражений - PullRequest
3 голосов
/ 05 июня 2019

Я новичок в Regex. Существуют данные в формате «(ENTITY A) - [: RELATION {}] -> (ENTITY B)», например, (Канберра) - [: capital_of {}] -> (Австралия). Как я могу извлечь две сущности и отношения?

Я пробовал следующий код:

path = "(Canberra)-[:capital_of {}]->(Australia)"
pattern = r'\(.*\)\-\[\:.*\]\-\>\(.*\)'
re.match(pattern,path).group()

Но это соответствует всему предложению. Любая помощь будет оценена.

Ответы [ 3 ]

5 голосов
/ 05 июня 2019

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

s="(Canberra)-[:capital_of {}]->(Australia)"
entityA = s[1:].split(')-')[0]
entityB = s.split('->(')[-1][:-1]

Входная строка разбивается на основе вхождения подстроки ')-', и первая часть берется для получения первогосущность.

split() выполняется на основе подстроки '->(', и для получения второй сущности выбирается последнее разбиение.

Итак,

print(f'EntityA: {entityA}')
print(f'EntityB: {entityB}')

даст

EntityA: Canberra
EntityB: Australia

Решения без регулярных выражений, как правило, быстрее.

Редактировать: Сроки согласно запросу в комментариях.

s="(Canberra)-[:capital_of {}]->(Australia)"
def regex_soln(s):
    pattern = r'\((.*)\)\-\[(:.*)\]\-\>\((.*)\)'
    rv = re.match(pattern,s).groups()
    return rv[0], rv[-1]

def non_regex_soln(s):
    return s[1:].split(')-')[0], s.split('->(')[-1][:-1]

%timeit regex_soln(s)
1.47 µs ± 60.8 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)


%timeit non_regex_soln(s)
619 ns ± 30.9 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
2 голосов
/ 05 июня 2019

Вы почти у цели. Вам нужно определить каждую группу, которую вы хотите захватить, заключив ее в ().

Код будет выглядеть как

import re
path = "(Canberra)-[:capital_of {}]->(Australia)"
pattern = r'\((.*)\)\-\[(:.*)\]\-\>\((.*)\)'
print(re.match(pattern,path).groups())

А на выходе будет

('Canberra', ':capital_of {}', 'Australia')
1 голос
/ 05 июня 2019

Это выглядит как некоторая DSL, d omain s pecific l anguage, так что вы могли бы очень хорошо написать для него небольшой анализатор.Здесь мы используем синтаксический анализатор PEG с именем parsimonious.

. Вам понадобится небольшая грамматика и класс NodeVisitor:

from parsimonious.grammar import Grammar
from parsimonious.nodes import NodeVisitor

path = "(Canberra)-[:capital_of {}]->(Australia)"

class PathVisitor(NodeVisitor):
    grammar = Grammar(
        r"""
        path    = (pair junk?)+
        pair    = lpar notpar rpar

        lpar    = ~"[(\[]+"
        rpar    = ~"[)\]]+"

        notpar  = ~"[^][()]+"
        junk    = ~"[-:>]+"
        """
    )

    def generic_visit(self, node, visited_children):
        return visited_children or node

    def visit_pair(self, node, visited_children):
        _, value, _ = visited_children
        return value.text

    def visit_path(self, node, visited_children):
        return [child[0] for child in visited_children]

pv = PathVisitor()
output = pv.parse(path)
print(output)

Что даст

['Canberra', ':capital_of {}', 'Australia']
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...