哪个正则表达式将匹配由逗号分隔的数字对,其中数字对由竖线分隔?

3

我目前正在尝试在Python上进行RegEx匹配,以匹配类似以下的输入:

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:

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

尝试2:
((((-?\d*\.?\d+,-?\d*\.?\d+)\|)+)|(-?\d*\.?\d+,-?\d*\.?\d+))

我希望有人之前就做过这个,或者有足够的正则表达式经验可以完成这样的事情。

2
预期输出是什么?获取所有的配对吗? - azro
你可以使用 split()。 - Jan
2
你想要拆分匹配还是匹配整个字符串? - The fourth bird
匹配整个字符串会很有用(我认为)。我想使用正则表达式来检测字符串是否符合该格式。 - freddiev4
4个回答

3

如果您想匹配整个字符串,可以匹配小数并重复以逗号为前缀的模式。

然后使用相同的模式,并将其以|为前缀进行重复。

^[+-]?\d+\.\d+(?:,[+-]?\d+\.\d+)*(?:\|[+-]?\d+\.\d+(?:,[+-]?\d+\.\d+)*)*$
  • ^ 字符串开头
  • [+-]?\d+\.\d+ 匹配可选的+-和小数部分
  • (?: 非捕获组
    • ,[+-]?\d+\.\d+ 匹配逗号后面的与前面相同的模式
  • )* 关闭组并重复0次或多次
  • (?: 非捕获组
    • \| 匹配|
    • [+-]?\d+\.\d+ 匹配可选的+-和小数部分
    • (?: 非捕获组
      • ,[+-]?\d+\.\d+ 匹配逗号后面的与前面相同的模式
    • )* 关闭组并重复0次或多次
  • )* 关闭组并重复0次或多次
  • $ 字符串结尾

正则表达式演示


3
这就是解析器的作用(检查正确的格式):
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: 

机器人的不正确:语句来自空行。


如果您真正想检索值,则需要编写另一个访问者类:

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))

2
你甚至不需要使用正则表达式。保持简单。
第一步
以逗号,为分隔符进行拆分。
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
真的没错(加1),但你甚至可以用你的保时捷去买点牛奶... - Jan

1
如果您想按键值对检索值,并且使用简单的正则表达式或仅使用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(",")

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接