首页 > 解决方案 > printf 样式格式字符串的解析器

问题描述

有没有一种很好的方法来解析 printf 样式的格式字符串并将各种位(文字文本和具有可处理选项的格式点)作为标准库的一部分,或者作为第三方库失败?我在标准库中找不到一个,而且网络搜索似乎没有发现任何有用的东西。

Python 2.6 添加了string.Formatter,它允许处理和自定义格式样式的字符串,但我没有找到类似的 printf 样式格式字符串的工具。

我正在寻找它来执行诸如验证翻译之类的事情,并可能将 printf 样式的格式字符串转换为格式样式的字符串(甚至是 f 字符串)。

标签: pythonparsingformatprintfstd

解决方案


在查看文档后,不难与 pyparsing 一起拍打:

import pyparsing as pp

# from https://docs.python.org/3/library/stdtypes.html?highlight=string%20interpolation#printf-style-string-formatting
PCT,LPAREN,RPAREN,DOT = map(pp.Literal, '%().')
conversion_flag_expr = pp.oneOf(list("#0- +"))
conversion_type_expr = pp.oneOf(list("diouxXeEfFgGcrsa%"))
length_mod_expr = pp.oneOf(list("hlL"))
interp_expr = (PCT
               + pp.Optional(LPAREN + pp.Word(pp.printables, excludeChars=")")("mapping_key") + RPAREN)
               + pp.Optional(conversion_flag_expr("conversion_flag"))
               + pp.Optional(('*' | pp.pyparsing_common.integer)("min_width"))
               + pp.Optional(DOT + pp.pyparsing_common.integer("max_width"))
               + pp.Optional(length_mod_expr("length_modifier"))
               + conversion_type_expr("conversion_type")
               )

tests = """
    Now is the winter of our %s made %(adjective)s %(season)s by this %(relative)s of %(city)s
    %(name)s, %(name)s, %(name)s, a %4.8d deaths were not enough for %(name)s 
""".splitlines()

for t in tests:
    print(t)
    for t,s,e in interp_expr.scanString(t):
        print("start: {} end: {}\n{}".format(s, e, t.dump()))
    print()

印刷:

Now is the winter of our %s made %(adjective)s %(season)s by this %(relative)s of %(city)s
start: 29 end: 31
['%', 's']
- conversion_type: 's'
start: 37 end: 50
['%', '(', 'adjective', ')', 's']
- conversion_type: 's'
- mapping_key: 'adjective'
start: 51 end: 61
['%', '(', 'season', ')', 's']
- conversion_type: 's'
- mapping_key: 'season'
start: 70 end: 82
['%', '(', 'relative', ')', 's']
- conversion_type: 's'
- mapping_key: 'relative'
start: 86 end: 94
['%', '(', 'city', ')', 's']
- conversion_type: 's'
- mapping_key: 'city'

%(name)s, %(name)s, %(name)s, a %4.8d deaths were not enough for %(name)s 
start: 4 end: 12
['%', '(', 'name', ')', 's']
- conversion_type: 's'
- mapping_key: 'name'
start: 14 end: 22
['%', '(', 'name', ')', 's']
- conversion_type: 's'
- mapping_key: 'name'
start: 24 end: 32
['%', '(', 'name', ')', 's']
- conversion_type: 's'
- mapping_key: 'name'
start: 36 end: 41
['%', 4, '.', 8, 'd']
- conversion_type: 'd'
- max_width: 8
- min_width: 4
start: 68 end: 76
['%', '(', 'name', ')', 's']
- conversion_type: 's'
- mapping_key: 'name'

如果您更喜欢正则表达式,那么将这个原型转换为可行的东西应该不难。


推荐阅读