Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/291.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,我正在尝试为以下表达式编写解析器 “每周从2017-11-03 15:00:00到2017-11-03 16:00:00到2017-12-03” 表示一个周期性的时间间隔。最后,我希望能够使用解析的字段初始化对象。大多数rrule参数是可选的,但是,在字符串表示中,这些参数对应于可能存在或不存在的模式 然而,我很难防止前面的模式“过于贪婪”。考虑以下两个测试用例: import re import pytest from dateutil.rrule import FREQNAMES def

我正在尝试为以下表达式编写解析器

“每周从2017-11-03 15:00:00到2017-11-03 16:00:00到2017-12-03”

表示一个周期性的时间间隔。最后,我希望能够使用解析的字段初始化对象。大多数
rrule
参数是可选的,但是,在字符串表示中,这些参数对应于可能存在或不存在的模式

然而,我很难防止前面的模式“过于贪婪”。考虑以下两个测试用例:

import re
import pytest

from dateutil.rrule import FREQNAMES

def match_pattern(string):
    SPACES = r'\s*'

    freq_names = [freq.lower() for freq in FREQNAMES] + [freq.title() for freq in FREQNAMES]
    FREQ_PATTERN = '(?P<freq>{})?'.format("|".join(freq_names))

    START_PATTERN = 'from' + SPACES + r'(?P<start>.+)'
    END_PATTERN = 'till' + SPACES + r'(?P<end>.+)'

    UNTIL_PATTERN = optional('until' + SPACES + r'(?P<until>.+)')
    # UNTIL_PATTERN = 'until' + SPACES + r'(?P<until>.+)'

    PATTERN = SPACES + FREQ_PATTERN \
            + SPACES + START_PATTERN \
            + SPACES + END_PATTERN \
            + SPACES + UNTIL_PATTERN + SPACES

    return re.match(PATTERN, string).groupdict()

def optional(pattern):
    '''Encloses the given regular expression in an optional group (i.e., one that matches 0 or 1 repetitions of the original regular expression).'''
    return '({})?'.format(pattern)

'''Tests'''
def test_match_pattern():
    string = "Weekly from 2017-11-03 15:00:00 till 2017-11-03 16:00:00"

    groups = match_pattern(string)
    assert groups['freq'] == "Weekly"
    assert groups['start'].strip() == "2017-11-03 15:00:00"
    assert groups['end'].strip() == "2017-11-03 16:00:00"

def test_match_pattern_with_until():
    string = "Weekly from 2017-11-03 15:00:00 till 2017-11-03 16:00:00 until 2017-12-03"

    groups = match_pattern(string)
    assert groups['freq'] == "Weekly"
    assert groups['start'].strip() == "2017-11-03 15:00:00"
    assert groups['end'].strip() == "2017-11-03 16:00:00"
    assert groups['until'].strip() == "2017-12-03"

if __name__ == "__main__":
    # pytest.main([__file__])
    pytest.main([__file__+"::test_match_pattern", "-s"])
    # pytest.main([__file__+"::test_match_pattern_with_until", "-s"])
问题是,当我将
UNTIL_模式
设置为可选模式时,
END_模式
太贪婪,会一直消耗到字符串的末尾。(如果我不将其设为
可选()
,则第二个测试通过,但第一个测试不产生匹配项)


如何使两个测试都通过?

您只需做两个小更改。首先,使
END_模式
非贪婪:

(?P<end>.+?)

你只需要做两个小改动。首先,使
END_模式
非贪婪:

(?P<end>.+?)

日期,如2017-11-03 15:00:00,似乎有一个相当标准的格式。尝试使用这些信息来帮助解析。实际上,您是在错误的顺序下进行的。必须先建立/修改/测试整个模式,然后再将其分解成碎片。这意味着必须首先测试每个意外事件。这可能意味着您必须丢失点元字符,并替换为更窄的子表达式。日期,如2017-11-03 15:00:00,似乎有一个相当标准的格式。尝试使用这些信息来帮助解析。实际上,您是在错误的顺序下进行的。必须先建立/修改/测试整个模式,然后再将其分解成碎片。这意味着必须首先测试每个意外事件。这可能意味着您必须丢失点元字符,并替换为更窄的子表达式。
PATTERN = SPACES + FREQ_PATTERN \
        + SPACES + START_PATTERN \
        + SPACES + END_PATTERN \
        + SPACES + UNTIL_PATTERN + SPACES + '$'