Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/regex/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Python中使用正则表达式对数据进行分组_Python_Regex - Fatal编程技术网

在Python中使用正则表达式对数据进行分组

在Python中使用正则表达式对数据进行分组,python,regex,Python,Regex,我有一些这样的原始数据: 亲爱的约翰买一杯可乐,10美元 伊凡买了20瓶牛奶 亲爱的蒂娜:买10瓶可乐,100美元 玛丽买了5瓶牛奶 数据的规则是: 并不是每个人都会以“亲爱的”开头,而如果有的话,则必须以成本结尾 该项目可能并不总是正常的话,它可以写没有限制(包括str,num等) 我想对信息进行分组,并尝试使用正则表达式。这就是我以前尝试过的: 用于文件中的行。readlines(): 匹配=重新搜索(r'\s+(?P\w+)\D*(?P\D+)\sof\s(?P\w+)(:\D+(?

我有一些这样的原始数据:

亲爱的约翰买一杯可乐,10美元 伊凡买了20瓶牛奶 亲爱的蒂娜:买10瓶可乐,100美元 玛丽买了5瓶牛奶 数据的规则是:

  • 并不是每个人都会以“亲爱的”开头,而如果有的话,则必须以成本结尾

  • 该项目可能并不总是正常的话,它可以写没有限制(包括str,num等)

我想对信息进行分组,并尝试使用正则表达式。这就是我以前尝试过的:

用于文件中的行。readlines():
匹配=重新搜索(r'\s+(?P\w+)\D*(?P\D+)\sof\s(?P\w+)(:\D+(?P\D*),第行)
如果匹配项不是无:
打印(match.groups())
file.close()文件
现在输出如下所示:

('John', '1', 'Coke', '10')
('Ivan', '20', 'Milk', '')
('Tina', '10', 'Coke', '100')
('Mary', '5', 'Milk', '')
显示以上是我想要的。但是,如果将
替换为一些奇怪的字符串,如
A1~A10
,则某些输出将获得错误的信息:

('Ivan', '20', 'A1', '10')
('Mary', '5', 'A1', '10')
我认为
项目字段
中的固定格式是它总是以
结尾(如果有)。但我只是不知道如何利用这个优势

虽然使用上面的代码暂时是成功的,但我认为必须像
(?p\w+)
一样替换
(?p.+)
。如果我这样做,它将在元组中使用错误的字符串,如:

('John', '1', 'Coke, cost 10 dollars', '')

如何使用Python中的正则表达式将数据读入所需的格式?

如果使用
+
,子模式将捕获行的整个剩余部分,因为
匹配任何字符,但不匹配
re.S
标志的换行符

您可以将
\w+
替换为否定字符类子模式
[^,]+
,以匹配除逗号以外的一个或多个字符:

r'\s+(?P<name>\w+)\D*(?P<num>\d+)\sof\s(?P<item>[^,]+)\D*(?P<costs>\d*)'
                                                ^^^^^

我会使用这个
regex

r'\s+(?P<name>\w+)\D*(?P<num>\d+)\sof\s(?P<item>[^,]+)(?:,\D+)?(?P<costs>\d+)?'
r'\s+(?P\w+)\D*(?P\D+)\sof\s(?P[^,]+)(?:,\D+)(?P\D+)
演示

>>> line = 'Dear   Tina    Buy  10 of A1~A10'
>>> match = re.search(r'\s+(?P<name>\w+)\D*(?P<num>\d+)\sof\s(?P<item>[^,]+)(?:,\D+)?(?P<costs>\d+)?', line)
>>> match.groups()
('Tina', '10', 'A1~A10', None)

>>> line = 'Dear   Tina    Buy  10 of A1~A10, cost 100 dollars'
>>> match = re.search(r'\s+(?P<name>\w+)\D*(?P<num>\d+)\sof\s(?P<item>[^,]+)(?:,\D+)?(?P<costs>\d+)?', line)
>>> match.groups()
('Tina', '10', 'A1~A10', '100')
>>行='亲爱的蒂娜,买10个A1~A10'
>>>匹配=重新搜索(r'\s+(?P\w+)\D*(?P\D+)\sof\s(?P[^,]+)(?:,\D+(?P\D+),行)
>>>match.groups()
('Tina','10','A1~A10',无)
>>>line='亲爱的Tina买10个A1~A10,花100美元'
>>>匹配=重新搜索(r'\s+(?P\w+)\D*(?P\D+)\sof\s(?P[^,]+)(?:,\D+(?P\D+),行)
>>>match.groups()
(‘蒂娜’、‘10’、‘A1~A10’、‘100’)
解释

正则表达式的第一部分非常好,下面是棘手的部分:

(?p[^,]+)
因为我们确信当成本字符串存在时,字符串将包含逗号,所以这里我们说,我们只需要逗号以外的任何东西来设置项目值

(?:,\D+)(?p\D+)
这里我们使用两个组。最重要的事情是
,在括住组的括号后:

“?”使生成的RE与 前RE。ab?将匹配“a”或“ab”

因此,我们使用
来匹配这两种可能性(成本字符串是否存在)

(?:,\D+)
是一个将匹配逗号后跟数字以外的任何内容的字符串


(?p\d+)
将捕获指定组成本中的任何数字。

我已尝试使用此正则表达式

^(亲爱的)?\s*(?p\w*)\D*(?p\D+)\sof\s(?p\w*)(,\D*(?p\D+)\D*)?

解释

  • ^(亲爱的)?
    匹配以
    亲爱的
    开头的行(如果存在)
  • (?P\w*)
    捕获名称的名称捕获组
  • \D*
    匹配任何非数字字符
  • (?P\d+
    命名捕获组以获取
    num
  • \sof\s
    匹配字符串的
    of
  • (?P\w*)
    取饮料
  • (,\D*(?P\D+)\D*)?
    这是获取饮料成本的可选组
  • 第一个数据段

    >>> data1 = 'Dear   John    Buy   1 of Coke, cost 10 dollars'
    >>> match_object = reobject.search(data1)
    >>> print (match_object.group('name') , match_object.group('num'), match_object.group('drink'), match_object.group('cost'))
    ('John', '1', 'Coke', '10')
    
    >>> data2 = '       Ivan    Buy  20 of Milk'
    >>> match_object = reobject.search(data2)
    >>> print (match_object.group('name') , match_object.group('num'), match_object.group('drink'), match_object.group('cost'))
    ('Ivan', '20', 'Milk', None)
    
    第二个数据段

    >>> data1 = 'Dear   John    Buy   1 of Coke, cost 10 dollars'
    >>> match_object = reobject.search(data1)
    >>> print (match_object.group('name') , match_object.group('num'), match_object.group('drink'), match_object.group('cost'))
    ('John', '1', 'Coke', '10')
    
    >>> data2 = '       Ivan    Buy  20 of Milk'
    >>> match_object = reobject.search(data2)
    >>> print (match_object.group('name') , match_object.group('num'), match_object.group('drink'), match_object.group('cost'))
    ('Ivan', '20', 'Milk', None)
    
    没有正则表达式:

    with open('commandes.txt') as f:
        results = []
        for line in f:
            parts = line.split(None, 5)
            price = ''
            if parts[0] == 'Dear':
                tmp = parts[5].split(',', 1)
                for tok in tmp[1].split():
                    if tok.isnumeric():
                        price = tok
                        break 
                results.append((parts[1], parts[3], tmp[0], price))
            else:
                results.append((parts[0], parts[2], parts[4].split(',')[0], price))
        print(results)
    
    在产品名称之前,它不在乎使用什么字符,除了空格,这就是为什么每一行用空格分成5部分的原因。当行以“亲爱的”开头时,最后一部分用逗号分隔,以提取产品名称和价格。请注意,如果价格始终在同一位置(即:在“成本”之后),则可以避免最内层的for循环,并将其替换为
    price=tmp[1].split()[1]

    注意:如果要防止处理空行,可以将第一个for循环更改为:

    for line in (x for x in f if x.rstrip()):
    

    你是说可乐可以是A1~A10吗?尝试使用
    (?P[^,]+)
    。我怀疑列之间用制表符分隔,您能确认吗?因为字段可以填充不同长度的数据,所以它们的空间不会固定。我认为<代码> [^,] +/<代码>是一个更好的主意。请考虑编辑你的帖子来添加更多关于你的代码所做的解释以及为什么它会解决这个问题。大多数情况下只包含代码的答案(即使有效)通常不会帮助OP理解他们的问题。完成;)@超偏见者
    for line in (x for x in f if x.rstrip()):