我试图为表示文件路径的字符串编写解析器,可选地后跟冒号(:
)和表示访问标记的字符串(例如r+
或{{ 1}})。文件名本身可以包含冒号,例如w
,因此分隔访问标志的冒号应该是字符串中的最后一个冒号。
到目前为止,这是我的实现:
foo:bar.txt
我已经尝试过以下测试:
import re
def parse(string):
SCHEME = r"file://" # File prefix
PATH_PATTERN = r"(?P<path>.+)" # One or more of any character
FLAGS_PATTERN = r"(?P<flags>.+)" # The letters r, w, a, b, a '+' symbol, or any digit
# FILE_RESOURCE_PATTERN = SCHEME + PATH_PATTERN + r":" + FLAGS_PATTERN + r"$" # This makes the first test pass, but the second one fail
FILE_RESOURCE_PATTERN = SCHEME + PATH_PATTERN + optional(r":" + FLAGS_PATTERN) + r"$" # This makes the second test pass, but the first one fail
tokens = re.match(FILE_RESOURCE_PATTERN, string).groupdict()
return tokens['path'], tokens['flags']
def optional(re):
'''Encloses the given regular expression in a group which matches 0 or 1 repetitions.'''
return '({})?'.format(re)
问题在于,通过使用或不使用import pytest
def test_parse_file_with_colon_in_file_name():
assert parse("file://foo:bar.txt:r+") == ("foo:bar.txt", "r+")
def test_parse_file_without_acesss_flags():
assert parse("file://foobar.txt") == ("foobar.txt", None)
if __name__ == "__main__":
pytest.main([__file__])
,我可以进行一个或另一个测试通过,但不能同时进行。如果我使optional
可选,则前面的正则表达式会占用整个字符串。
如何调整r":" + FLAGS_PATTERN
方法以使两个测试都通过?
答案 0 :(得分:1)
你应该建立像
这样的正则表达式^file://(?P<path>.+?)(:(?P<flags>[^:]+))?$
请参阅regex demo。
在您的代码中,^
锚点不是必需的,因为您使用re.match
在字符串的开头锚定匹配项。 path
组可以懒惰地匹配任何1个字符(因此,所有可以与第2组匹配的文本将在第二次捕获中着陆),直到第一次出现:
后跟1+个字符除了:
(如果存在),然后测试字符串位置的结尾。感谢$
锚点,如果第二个可选组不匹配,第一个组将匹配整个字符串。
使用以下修复程序:
PATH_PATTERN = r"(?P<path>.+?)" # One or more of any character
FLAGS_PATTERN = r"(?P<flags>[^:]+)" # The letters r, w, a, b, a '+' symbol, or any digit
答案 1 :(得分:1)
为了好玩,我写了这个解析函数,我认为这比使用RE更好?
def parse(string):
s = string.split('//')[-1]
try:
path, flags = s.rsplit(':', 1)
except ValueError:
path, flags = s.rsplit(':', 1)[0], None
return path, flags