Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/354.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_Parsing_Units Of Measurement - Fatal编程技术网

Python 使用组和嵌套正则表达式进行组命名(从文本文件进行单位转换)

Python 使用组和嵌套正则表达式进行组命名(从文本文件进行单位转换),python,regex,parsing,units-of-measurement,Python,Regex,Parsing,Units Of Measurement,基本问题: 如何用另一个组值命名python正则表达式组,并将其嵌套在更大的正则表达式组中 问题来源: 给定一个字符串,如,您最喜欢的歌曲长度为1小时23秒。我的手机只记录1小时30分10秒。 提取时间并转换为给定单位的优雅解决方案是什么 尝试的解决方案: 我对解决方案的最佳猜测是创建一个字典,然后对字典执行操作以转换为所需的单元 i、 e.将给定字符串转换为: string[0]: {'time1': {'day':0, 'hour':1, 'minutes':0, 'seconds':23

基本问题:

如何用另一个组值命名python正则表达式组,并将其嵌套在更大的正则表达式组中

问题来源:

给定一个字符串,如
,您最喜欢的歌曲长度为1小时23秒。我的手机只记录1小时30分10秒。

提取时间并转换为给定单位的优雅解决方案是什么

尝试的解决方案:

我对解决方案的最佳猜测是创建一个字典,然后对字典执行操作以转换为所需的单元

i、 e.将给定字符串转换为:

string[0]:
 {'time1': {'day':0, 'hour':1, 'minutes':0, 'seconds':23, 'milliseconds':0}, 'time2': {'day':0, 'hour':1, 'minutes':30, 'seconds':10, 'milliseconds':0}}

string[1]:
 {'time1': {'day':4, 'hour':2, 'minutes':3, 'seconds':6, 'milliseconds':30}}
我有一个正则表达式解决方案,但它没有达到我想要的效果:

import re

test_string = ['Your favorite song is 1 hour 23 seconds long.  My phone only records for 1h 30 mins and 10 secs.',
                'This video is 4 days 2h 3min 6sec 30ms']

year_units = ['year', 'years', 'y']
day_units = ['day', 'days', 'd']
hour_units = ['hour', 'hours', 'h']
min_units = ['minute', 'minutes', 'min', 'mins', 'm']
sec_units = ['second', 'seconds', 'sec', 'secs', 's']
millisec_units = ['millisecond', 'milliseconds', 'millisec', 'millisecs', 'ms']
all_units = '|'.join(year_units + day_units + hour_units + min_units + sec_units + millisec_units)
print((all_units))

# pattern = r"""(?P<time>               # time group beginning
#               (?P<value>[\d]+)    # value of time unit
#               \s*                 # may or may not be space between digit and unit
#               (?P<unit>%s)        # unit measurement of time
#               \s*                 # may or may not be space between digit and unit
#           )
#           \w+""" % all_units
pattern = r""".*(?P<time>       # time group beginning
            (?P<value>[\d]+)    # value of time unit
            \s*                 # may or may not be space between digit and unit
            (?P<unit>%s)        # unit measurement of time
            \s*                 # may or may not be space between digit and unit
            ).*                 # may be words in between the times 
            """ % (all_units)

regex = re.compile(pattern)
for val in test_string:
    match = regex.search(val)
    print(match)
    print(match.groupdict())
重新导入
test_string=[“你最喜欢的歌曲是1小时23秒长。我的手机只录制1小时30分10秒。”,
“此视频为4天2小时3分钟6秒30毫秒”]
年份单位=[‘年’、‘年’、‘y’]
日单位=[‘日’、‘日’、‘d']
小时单位=['hour','hours','h']
最小单位=[‘分钟’、‘分钟’、‘分钟’、‘分钟’、‘米’]
秒单位=[‘秒’、‘秒’、‘秒’、‘秒’、‘s’]
毫秒单位=[“毫秒”、“毫秒”、“毫秒”、“毫秒”、“毫秒”、“毫秒”]
所有单位=“|”。加入(年单位+日单位+小时单位+分钟单位+秒单位+毫秒单位)
打印((所有单位))
#模式=r”“”(?P#时间组开始
#(?P[\d]+)#时间单位值
#\s*#可能是也可能不是数字和单位之间的空格
#(?P%s)#时间单位测量
#\s*#可能是也可能不是数字和单位之间的空格
#           )
#\w+“”%s所有\u单元
模式=r”“*(?P#时间组开始
(?P[\d]+)#时间单位值
\s*#可能是也可能不是数字和单位之间的空格
(?P%s)#时间单位测量
\s*#可能是也可能不是数字和单位之间的空格
).#可能是介于时间之间的词语
“%”(所有单位)
regex=re.compile(模式)
对于测试字符串中的val:
match=regex.search(val)
打印(匹配)
打印(match.groupdict())

由于无法正确处理嵌套分组,并且无法使用组的值指定名称,因此此操作失败得很惨。

首先,如果不使用
re.VERBOSE
标志,您不能只编写带注释的多行正则表达式并期望它匹配任何内容:

regex = re.compile(pattern, re.VERBOSE)

正如你所说,最好的解决办法可能是使用dict

for val in test_string:
    while True: #find all times
        match = regex.search(val) #find the first unit
        if not match:
            break
        matches= {} # keep track of all units and their values
        while True:
            matches[match.group('unit')]= int(match.group('value')) # add the match to the dict
            val= val[match.end():] # remove part of the string so subsequent matches must start at index 0
            m= regex.search(val)
            if not m or m.start()!=0: # if there are no more matches or there's text between this match and the next, abort
                break
            match= m
        print matches # the finished dict

# output will be like {'h': 1, 'secs': 10, 'mins': 30}
然而,上面的代码还不能工作。我们需要作出两项调整:

  • 模式不能只允许匹配之间有任何文本。要在两个匹配项之间仅允许空白和“and”一词,可以使用

    pattern=r”“(?p#时间组开始
    (?P[\d]+)#时间单位值
    \s*#可能是也可能不是数字和单位之间的空格
    (?P%s)#时间单位测量
    \s*#可能是也可能不是数字和单位之间的空格
    (?:\band\s+)#允许数字之间使用“和”字
    )#可能是介于时间之间的词语
    “%”(所有单位)

  • 你必须改变你单位的顺序,如下所示:

    year_单位=['years'、'year'、'y']#年前年份
    日单位=['days','day','d']#日前几天等。

    为什么??因为如果你有一个像
    3年1天
    这样的文本,那么它将匹配
    3年
    ,而不是
    3年和


哇!非常感谢,这是一个极好的解决方案!关于排序的好的一点是,我甚至没有想到,如果没有“s”,它会匹配,直到你写出来。