parse() 是 format() 的反义词
项目描述
安装
pip install parse
用法
使用基于Python format()语法的规范解析字符串。
parse() 是 format() 的反义词
当使用 import * 时,该模块配置为仅导出 parse()、search()、findall() 和 with_pattern()
>>> from parse import *
然后就可以简单地解析一个字符串
>>> parse("It's {}, I love it!", "It's spam, I love it!")
<Result ('spam',) {}>
>>> _[0]
'spam'
或者搜索一个字符串以查找某些模式
>>> search('Age: {:d}\n', 'Name: Rufus\nAge: 42\nColor: red\n')
<Result (42,) {}>
或者在字符串中查找某些模式的所有出现
>>> ''.join(r[0] for r in findall(">{}<", "<p>the <b>bold</b> text</p>"))
'the bold text'
如果您打算使用相同的模式匹配多个字符串,您可以一次性编译它
>>> from parse import compile
>>> p = compile("It's {}, I love it!")
>>> print(p)
<Parser "It's {}, I love it!">
>>> p.parse("It's spam, I love it!")
<Result ('spam',) {}>
(“compile” 在 import * 使用中未导出,因为它会覆盖内置的 compile() 函数)
默认行为是不区分大小写地匹配字符串。你可以通过指定 case_sensitive=True 来进行大小写匹配。
>>> parse('SPAM', 'spam', case_sensitive=True) is None
True
格式语法
支持基本版本的 格式字符串语法,包括匿名(固定位置)、命名和格式化字段。
{[field name]:[format spec]}
字段名必须是有效的 Python 标识符,包括点分隔的名称;元素索引表示字典(以下示例中说明)。
不支持编号字段:解析的结果将按解析顺序包含解析的字段。
字段转换为除字符串以外的类型是基于格式规范中的类型,这与 format() 的行为相一致。没有类似于 format() 中的“!”字段转换。
一些简单的 parse() 格式字符串示例
>>> parse("Bring me a {}", "Bring me a shrubbery")
<Result ('shrubbery',) {}>
>>> r = parse("The {} who {} {}", "The knights who say Ni!")
>>> print(r)
<Result ('knights', 'say', 'Ni!') {}>
>>> print(r.fixed)
('knights', 'say', 'Ni!')
>>> print(r[0])
knights
>>> print(r[1:])
('say', 'Ni!')
>>> r = parse("Bring out the holy {item}", "Bring out the holy hand grenade")
>>> print(r)
<Result () {'item': 'hand grenade'}>
>>> print(r.named)
{'item': 'hand grenade'}
>>> print(r['item'])
hand grenade
>>> 'item' in r
True
注意,in 只在存在命名字段时才有效。
点分隔的名称和索引是可能的,但有一些限制。只支持单词标识符(即不允许数字索引),并且应用程序必须对结果进行额外的解释。
>>> r = parse("Mmm, {food.type}, I love it!", "Mmm, spam, I love it!")
>>> print(r)
<Result () {'food.type': 'spam'}>
>>> print(r.named)
{'food.type': 'spam'}
>>> print(r['food.type'])
spam
>>> r = parse("My quest is {quest[name]}", "My quest is to seek the holy grail!")
>>> print(r)
<Result () {'quest': {'name': 'to seek the holy grail!'}}>
>>> print(r['quest'])
{'name': 'to seek the holy grail!'}
>>> print(r['quest']['name'])
to seek the holy grail!
如果你要匹配的文本中有花括号,你可以在格式字符串中包含双花括号 {{ 或 }} 来匹配这些花括号,就像 format() 一样。
格式规范
通常,在不使用更复杂的格式规范的情况下,使用直接的无格式 {} 就足够了。
大部分 format() 的 格式规范迷你语言 都得到了支持。
[[填充]对齐][符号][0][宽度][.精度][类型]
parse() 和 format() 之间的区别是:
对齐运算符会导致从解析值中移除空格(或指定的填充字符)。宽度不是强制性的;它只是表示可能存在空格或“0”需要移除。
数字解析会自动处理“0b”、“0o”或“0x”前缀。即,“#”格式字符会自动由 d、b、o 和 x 格式处理。对于“d”,任何前缀都可以接受,但对于其他格式,如果存在,则必须具有正确的前缀。
数字符号会自动处理。可以提供符号指定符,但它没有效果。
如果使用“n”类型,则会自动处理千位分隔符。
支持的类型与 format() 类型略有不同。一些 format() 类型直接映射过来:“d”、“n”、“%”、“f”、“e”、“b”、“o”和“x”。此外,一些正则表达式字符组类型“D”、“w”、“W”、“s”和“S”也是可用的。
“e”和“g”类型不区分大小写,因此不需要“E”或“G”类型。“e”类型处理 Fortran 格式的数字(小数点前没有前导 0)。
类型 |
匹配的字符 |
输出 |
---|---|---|
l |
字母(ASCII) |
str |
w |
字母、数字和下划线 |
str |
W |
非字母、数字和下划线 |
str |
s |
空白字符 |
str |
S |
非空白字符 |
str |
d |
数字(实际上是整数) |
int |
D |
非数字 |
str |
n |
带千位分隔符的数字(, 或 .) |
int |
% |
百分比(转换为值/100.0) |
float |
f |
定点数 |
float |
F |
十进制数 |
Decimal |
e |
带有指数的浮点数,例如 1.1e-10,NAN(所有大小写不敏感) |
float |
g |
通用数字格式(d、f 或 e) |
float |
b |
二进制数 |
int |
o |
八进制数 |
int |
x |
十六进制数(大小写不敏感) |
int |
ti |
ISO 8601 格式的日期/时间,例如 1972-01-20T10:21:36Z(“T”和“Z”可选) |
datetime |
te |
RFC2822 电子邮件格式日期/时间,例如 Mon, 20 Jan 1972 10:21:36 +1000 |
datetime |
tg |
全球(日/月)格式日期/时间,例如 20/1/1972 10:21:36 AM +1:00 |
datetime |
ta |
美国(月/日)格式日期/时间,例如 1/20/1972 10:21:36 PM +10:30 |
datetime |
tc |
ctime()日期/时间格式,例如:Sun Sep 16 01:03:52 1973 |
datetime |
th |
HTTP日志格式日期/时间,例如:21/Nov/2011:00:07:11 +0000 |
datetime |
ts |
Linux系统日志格式日期/时间,例如:Nov 9 03:37:44 |
datetime |
tt |
时间,例如:10:21:36 PM -5:30 |
time |
类型也可以是日期时间格式字符串,遵循1989年C标准格式代码,例如%Y-%m-%d。根据格式字符串中包含的指令,解析输出可能是datetime.datetime、datetime.time或datetime.date的一个实例。
>>> parse("{:%Y-%m-%d %H:%M:%S}", "2023-11-23 12:56:47")
<Result (datetime.datetime(2023, 11, 23, 12, 56, 47),) {}>
>>> parse("{:%H:%M}", "10:26")
<Result (datetime.time(10, 26),) {}>
>>> parse("{:%Y/%m/%d}", "2023/11/25")
<Result (datetime.date(2023, 11, 25),) {}>
以下是一些类型解析的示例,如果类型不匹配则返回None
>>> parse('Our {:d} {:w} are...', 'Our 3 weapons are...')
<Result (3, 'weapons') {}>
>>> parse('Our {:d} {:w} are...', 'Our three weapons are...')
>>> parse('Meet at {:tg}', 'Meet at 1/2/2011 11:00 PM')
<Result (datetime.datetime(2011, 2, 1, 23, 0),) {}>
并且与对齐有关的问题
>>> parse('with {:>} herring', 'with a herring')
<Result ('a',) {}>
>>> parse('spam {:^} spam', 'spam lovely spam')
<Result ('lovely',) {}>
请注意,“居中”对齐并不检查值是否居中,它只是删除前导和尾随空白。
宽度和精度可用于限制从输入中匹配的文本的大小。宽度指定最小大小,而精度指定最大大小。例如
>>> parse('{:.2}{:.2}', 'look') # specifying precision
<Result ('lo', 'ok') {}>
>>> parse('{:4}{:4}', 'look at that') # specifying width
<Result ('look', 'at that') {}>
>>> parse('{:4}{:.4}', 'look at that') # specifying both
<Result ('look at ', 'that') {}>
>>> parse('{:2d}{:2d}', '0440') # parsing two contiguous numbers
<Result (4, 40) {}>
有关特殊日期和时间类型的说明
时间部分是可选的(包括ISO 8601,从“T”开始)。始终将返回完整的日期时间对象;时间将设置为00:00:00。您还可以指定不包含秒的时间。
如果输入中存在秒数,则将解析分数以给出微秒。
除ISO 8601外,日期和月份数字可以是0填充的。
tg和ta格式的日期分隔符可以是“-”或“/”。
在ta和tg格式中,可以使用名称月份(缩写或全称)代替数字月份。
根据RFC 2822,电子邮件格式可以省略日期(和逗号)、秒数,但不能省略其他内容。
大于12小时的小时数将被愉快地接受。
AM/PM是可选的,如果找到PM,则将向日期时间对象的时数添加12小时 - 即使小时数大于12(为了保持一致)。
在ISO 8601中,“Z”(UTC)时区部分可以是数字偏移量
时区指定为“+HH:MM”或“-HH:MM”。小时数可以是1或2位数字(0填充是可接受的)。此外,“:”是可选的。
时区在电子邮件格式之外都是可选的(默认为UTC)。
尚未处理命名时区。
注意:尝试在单个解析()中匹配过多的日期时间字段,当前将导致资源分配问题。在这种情况下将引发TooManyFields异常。当前的限制约为15。希望有一天会取消这个限制。
结果和匹配对象
parse()和search()操作的结果要么是None(没有匹配),要么是Result实例,或者如果evaluate_result为False,则是Match实例。
Result实例有三个属性
- fixed
从输入中提取的固定位置、匿名字段的元组。
- named
从输入中提取的命名字段的字典。
- spans
将名称和固定位置索引映射到在输入中匹配发生的位置的2元组切片范围的字典。范围不包括任何被删除的填充(对齐或宽度)。
Match实例有一个方法
- evaluate_result()
为此Match对象生成并返回一个Result实例。
自定义类型转换
如果您希望自动将匹配的字段转换为您的类型,您可以将类型转换信息字典传递给parse()和compile()。
转换器将传递匹配的字段字符串。它返回的内容将被替换到该字段的结果实例中。
如果您提供了一个与内置类型具有相同标识符的自定义类型转换,则可以覆盖内置类型。
>>> def shouty(string):
... return string.upper()
...
>>> parse('{:shouty} world', 'hello world', {"shouty": shouty})
<Result ('HELLO',) {}>
如果类型转换器具有可选的模式属性,它将被用作正则表达式以进行更好的模式匹配(而不是默认模式)。
>>> def parse_number(text):
... return int(text)
>>> parse_number.pattern = r'\d+'
>>> parse('Answer: {number:Number}', 'Answer: 42', {"Number": parse_number})
<Result () {'number': 42}>
>>> _ = parse('Answer: {:Number}', 'Answer: Alice', {"Number": parse_number})
>>> assert _ is None, "MISMATCH"
您还可以使用with_pattern(pattern)装饰器将此信息添加到类型转换器函数中。
>>> from parse import with_pattern
>>> @with_pattern(r'\d+')
... def parse_number(text):
... return int(text)
>>> parse('Answer: {number:Number}', 'Answer: 42', {"Number": parse_number})
<Result () {'number': 42}>
一个自定义类型的更完整示例可能如下
>>> yesno_mapping = {
... "yes": True, "no": False,
... "on": True, "off": False,
... "true": True, "false": False,
... }
>>> @with_pattern(r"|".join(yesno_mapping))
... def parse_yesno(text):
... return yesno_mapping[text.lower()]
如果类型转换器的模式使用正则表达式分组(带有括号),您应该通过在with_pattern()装饰器中使用可选的regex_group_count参数来指出这一点。
>>> @with_pattern(r'((\d+))', regex_group_count=2)
... def parse_number2(text):
... return int(text)
>>> parse('Answer: {:Number2} {:Number2}', 'Answer: 42 43', {"Number2": parse_number2})
<Result (42, 43) {}>
否则,这可能会导致解析问题,涉及无名称/固定参数。
潜在问题
parse()始终匹配满足解析模式的最短文本(从左到右),因此例如
>>> pattern = '{dir1}/{dir2}'
>>> data = 'root/parent/subdir'
>>> sorted(parse(pattern, data).named.items())
[('dir1', 'root'), ('dir2', 'parent/subdir')]
因此,尽管{‘dir1’: ‘root/parent’, ‘dir2’: ‘subdir’}也符合模式,但实际上匹配的是dir1的最短成功匹配。
开发者
想要为parse做出贡献?将仓库Fork到您的GitHub账户,并创建一个pull-request。
git clone git@github.com:r1chardj0n3s/parse.git
git remote rename origin upstream
git remote add origin git@github.com:YOURUSERNAME/parse.git
git checkout -b myfeature
要本地运行测试
python -m venv .venv
source .venv/bin/activate
pip install -r tests/requirements.txt
pip install -e .
pytest
变更日志
1.20.2 模板字段名称现在可以包含短横线字符,即连字符(chr(0x2d))。
1.20.1 %f指令接受1-6位数字,类似于strptime(感谢@bbertincourt)。
1.20.0 增加了strptime代码的支持(感谢@bendichter)。
1.19.1 增加了数字格式中的符号说明符的支持(感谢@anntzer)。
1.19.0 增加了固定结果的切片访问(感谢@jonathangjertsen)。还纠正了全文与全文行的匹配问题(感谢@giladreti)。修复了使用数字字段编号和类型的问题。
1.18.0 修复了1.16.0中引入的int解析错误(感谢@maxxk)。
1.17.0 使左对齐和居中对齐搜索消耗到下一个空格。
1.16.0 使编译的解析对象可序列化(感谢@martinResearch)。
1.15.0 对非十进制数字的解析进行了多项修复(感谢@vladikcomper)。
1.14.0 更广泛地接受Fortran数字格式(感谢@purpleskyfall)。
1.13.1 项目元数据更正。
1.13.0 处理没有小数点前零的Fortran格式数字(感谢@purpleskyfall)。处理FixedTzOffset与其他类型对象的比较。
1.12.1 实际使用compile中的case_sensitive参数(感谢@jacquev6)。
1.12.0 在找到开括号时不假设有闭括号(感谢@mattsep)。
1.11.1 回滚docstring中的unicode字符,因为它破坏了Bamboo构建(?!)
1.11.0 实现了Result实例的__contains__。
1.10.0 引入了一个“letters”匹配器,因为“w”也会匹配数字。
1.9.1 修复了正则表达式字符串中的反斜杠的弃用警告(感谢Mickael Schoentgen)。还修复了一些文档格式问题。
1.9.0 现在在解析数字和字符串时尊重精度和宽度说明符,允许解析固定宽度的连接元素(感谢Julia Signell)。
1.8.4 根据打包者的请求添加了LICENSE文件。更正了AM/PM的处理,以遵循最普遍的解释。更正了类似二进制前缀的十六进制解析。添加了以“F”将数字解析到Decimal的能力。添加了解析大小写敏感的能力(感谢John Vandenberg)。
1.8.3 在with_pattern()装饰器中添加了regex_group_count,以支持包含括号/括号的用户定义类型(感谢Jens Engel)。
1.8.2 为包括花括号在格式字符串中添加了文档。
1.8.1 确保纯十六进制数字不被匹配。
1.8.0 支持手动控制结果评估(感谢Timo Furrer)。
1.7.0 解析字典字段(感谢Mark Visser)并适配Python 3.5+中的100多个正则表达式组(感谢David King)。
1.6.6 解析Linux系统日志日期(感谢Alex Cowan)。
1.6.5 处理浮点格式中的精度(感谢 Levi Kilcher)
1.6.4 处理解析字符串中的管道“|”字符(感谢 Martijn Pieters)
1.6.3 处理命名字段的重复实例,修复 PM 时间溢出错误
1.6.2 修复日志记录使用本地记录器,而不是根记录器(感谢 Necku)
1.6.1 在匹配 ISO 日期时间和时区方面更具灵活性,修复没有“:”的时区错误,并改进文档
1.6.0 在用户定义类型中添加对可选 pattern 属性的支持(感谢 Jens Engel)
1.5.3 修复处理问号的问题
1.5.2 修复使用点名称的错误类型转换(感谢 Sebastian Thiel)
1.5.1 实现处理命名日期时间字段
1.5 添加对点字段名称的处理(感谢 Sebastian Thiel)
1.4.1 修复 int 转换中“0”的解析(感谢 James Rowe)
1.4 在 Result 中添加 __getitem__ 便利访问
1.3.3 修复 Python 2.5 setup.py 的问题。
1.3.2 修复 Python 3.2 setup.py 的问题。
1.3.1 修复一些 Python 3.2 兼容性问题。
1.3 添加 search() 和 findall();从 import * 导出时移除 compile(),因为它会覆盖内置函数。
1.2 添加自定义和重写类型转换的能力;进行一些清理
1.1.9 为了使事情更简单,自动处理数字符号;针对边缘情况输入进行显著的健壮性改进。
1.1.8 允许“d”字段具有“0x”等数字基前缀;在压力测试解析器后修复一些字段类型交互;实现“%”类型。
1.1.7 Python 3 兼容性调整(支持 2.5 到 2.7 和 3.2)。
1.1.6 添加“e”和“g”字段类型;删除冗余的“h”和“X”;删除显式“#”的需求。
1.1.5 在更多地方接受文本日期;Result 现在保留匹配的跨度位置。
1.1.4 对某些 int 类型转换进行修复;实现“=”对齐;添加支持多种格式的日期/时间解析。
1.1.3 类型转换根据指定的字段类型自动进行。还添加了“f”和“n”类型。
1.1.2 重构,添加 compile() 和有限 from parse import * 导出
1.1.1 改进文档
1.1.0 实现了更多 格式规范迷你语言 的功能,并删除了混合固定位置和命名字段的限制
1.0.0 首次发布
本代码版权所有 2012-2021 Richard Jones <richard@python.org> 请参阅源文件末尾的使用许可。
项目详情
下载文件
下载您平台上的文件。如果您不确定选择哪个,请了解更多关于 安装软件包 的信息。
源代码分发
构建的发行版
parse-1.20.2.tar.gz 的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | b41d604d16503c79d81af5165155c0b20f6c8d6c559efa66b4b695c3e5a0a0ce |
|
MD5 | 129951f4c2cece0ca6df437b522391e3 |
|
BLAKE2b-256 | 4f78d9b09ba24bb36ef8b83b71be547e118d46214735b6dfb39e4bfde0e9b9dd |
parse-1.20.2-py2.py3-none-any.whl 的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 967095588cb802add9177d0c0b6133b5ba33b1ea9007ca800e526f42a85af558 |
|
MD5 | f1e7a7099bbe63023caae35ec743dbb0 |
|
BLAKE2b-256 | d031ba45bf0b2aa7898d81cbbfac0e88c267befb59ad91a19e36e1bc5578ddb1 |