Какое регулярное выражение будет соответствовать парам чисел, разделенных запятыми, с парами, разделенными трубами? - PullRequest
3 голосов
/ 04 ноября 2019

В настоящее время я пытаюсь сопоставить RegEx (в Python) с входными данными, которые выглядят следующим образом:

37.1000,-88.1000
37.1000,-88.1000|37.1450,-88.1060
37.1000,-88.1000|37.1450,-88.1060|35.1450,-83.1060

Итак, пары десятичных чисел, разделенные запятыми, а затем эти пары (если> 1 пара)разделены |. Я пробовал несколько вещей, но не могу получить строку регулярного выражения, которая соответствует должным образом.

Попытка 1:

((((\d*\.?\d+,\d*\.?\d+)\|)+)|(\d*\.?\d+,\d*\.?\d+))

Попытка 2:

((((-?\d*\.?\d+,-?\d*\.?\d+)\|)+)|(-?\d*\.?\d+,-?\d*\.?\d+))

Iнадеялся, что кто-то мог сделать это раньше, или у него достаточно опыта в RegEx, чтобы сделать что-то подобное.

Ответы [ 4 ]

3 голосов
/ 04 ноября 2019

Это то, для чего предназначены парсеры (то есть, проверяя правильный формат):

from parsimonious.grammar import Grammar

data = """
37.1000,-88.1000
37.1000,-88.1000|37.1450,-88.1060
37.1000,-88.1000|37.1450,-88.1060|35.1450,-83.1060
"""

grammar = Grammar(
    r"""
    line    = pair (pipe pair)*
    pair    = point ws? comma ws? point
    point   = ~"-?\d+(?:.\d+)?"
    comma   = ","
    pipe    = "|"
    ws      = ~"\s+"
    """
)


for line in data.split("\n"):
    try:
        grammar.parse(line)
        print("Correct format: {}".format(line))
    except:
        print("Not correct: {}".format(line))

Это даст

Not correct: 
Correct format: 37.1000,-88.1000
Correct format: 37.1000,-88.1000|37.1450,-88.1060
Correct format: 37.1000,-88.1000|37.1450,-88.1060|35.1450,-83.1060
Not correct: 

Bot Not correct: операторов, взятых из пустых строк,


Если вы действительно хотите получить значения, вам нужно написать еще один Visitor класс:
class Points(NodeVisitor):
    grammar = Grammar(
        r"""
        line    = pair (pipe pair)*
        pair    = point ws? comma ws? point
        point   = ~"-?\d+(?:.\d+)?"
        comma   = ","
        pipe    = "|"
        ws      = ~"\s+"
        """
    )

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

    def visit_pair(self, node, visited_children):
        x, *_, y = visited_children
        return (x.text, y.text)

    def visit_line(self, node, visited_children):
        pairs = [visited_children[0]]
        for potential_pair in [item[1] for item in visited_children[1]]:
            pairs.append(potential_pair)
        return pairs

point = Points()
for line in data.split("\n"):
    try:
        pairs = point.parse(line)
        print(pairs)
    except ParseError:
        print("Not correct: {}".format(line))
3 голосов
/ 04 ноября 2019

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

Затем используйте тот же шаблон и повторите тот же шаблон, которому предшествует |

^[+-]?\d+\.\d+(?:,[+-]?\d+\.\d+)*(?:\|[+-]?\d+\.\d+(?:,[+-]?\d+\.\d+)*)*$
  • ^ Начало строки
  • [+-]?\d+\.\d+ Соответствует необязательному + или - и десятичной части
  • (?: Группа без захвата
    • ,[+-]?\d+\.\d+ Совпадение с тем же шаблоном, что и раньше, с добавлением запятой
  • )* Закрыть группу и повторить 0+ раз
  • (?: Негруппа захвата
    • \| совпадение |
    • [+-]?\d+\.\d+ сопоставление необязательного + или - и десятичной части
    • (?: группа без захвата
      • ,[+-]?\d+\.\d+ Совпадение с тем же шаблоном, что и раньше, с добавлением запятой
    • )* Закрыть группу и повторить 0+ раз
  • )* Закрыть группу и повторить 0+ раз
  • $ Конец строки

regex demo

2 голосов
/ 04 ноября 2019

Вам даже не нужно регулярное выражение для этого. Сохраняйте это простым.

Шаг 1

Разделите на ,.

s.split(',')

Шаг 2

Разделите на | и обеспечьте каждый результатимеет тип float (скорее, он может быть преобразован в этот тип без ошибок). Второй шаг здесь (проверка) может быть удален, если он не требуется.

r = s.split('|')
for v in r:
    try:
        float(v)
    except ValueError:
        print(v + ' is not a float')

Шаг 3

Объединение.

Проверьте его здесь

strings = [
    '37.1000,-88.1000',
    '37.1000,-88.1000|37.1450,-88.1060',
    '37.1000,-88.1000|37.1450,-88.1060|35.1450,-83.1060'
]

def split_on_comma(s):
    return s.split(',')

def split_on_bar(s):
    r = s.split('|')
    for v in r:
        try:
            float(v)
        except ValueError:
            print(v + ' is not a float')
    return r

for s in strings:
    for c in split_on_comma(s):
        print(split_on_bar(c))

Без проверки и функций ваш код становится:

for s in strings:
    for c in s.split(','):
        for b in c.split('|'):
            print(b)

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

1 голос
/ 04 ноября 2019

Если вы хотите получить значение по парам и используете простое регулярное выражение или просто split()

for value in values:
    pairs = re.findall("([\d. ,-]+)\|?", value)
    for pair in pairs:
        v1, v2 = pair.strip().split(",")
# or
for value in values:
    pairs = value.split("|")
    for pair in pairs:
        v1, v2 = pair.strip().split(",")
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...