evs*_*ith 28 python string-formatting
我有形式的字符串Version 1.4.0\n和Version 1.15.6\n,我想从他们身上抽取三个数字的简单方法.我知道我可以使用format方法将变量放入字符串中; 我基本上想要倒退,像这样:
# So I know I can do this:
x, y, z = 1, 4, 0
print 'Version {0}.{1}.{2}\n'.format(x,y,z)
# Output is 'Version 1.4.0\n'
# But I'd like to be able to reverse it:
mystr='Version 1.15.6\n'
a, b, c = mystr.unformat('Version {0}.{1}.{2}\n')
# And have the result that a, b, c = 1, 15, 6
Run Code Online (Sandbox Code Playgroud)
我找到的其他人问了同样的问题,但回复是针对他们的特定情况的: 反向使用Python格式字符串进行解析
一般答案(如何format()反向)会很棒!我的具体案例的答案也会非常有用.
>>> import re
>>> re.findall('(\d+)\.(\d+)\.(\d+)', 'Version 1.15.6\n')
[('1', '15', '6')]
Run Code Online (Sandbox Code Playgroud)
只是为了建立在Uche的答案上,我一直在寻找一种通过kwargs模式来反转字符串的方法.所以我把以下功能放在一起:
def string_to_dict(string, pattern):
regex = re.sub(r'{(.+?)}', r'(?P<_\1>.+)', pattern)
values = list(re.search(regex, string).groups())
keys = re.findall(r'{(.+?)}', pattern)
_dict = dict(zip(keys, values))
return _dict
Run Code Online (Sandbox Code Playgroud)
其工作原理如下:
>>> p = 'hello, my name is {name} and I am a {age} year old {what}'
>>> s = p.format(name='dan', age=33, what='developer')
>>> s
'hello, my name is dan and I am a 33 year old developer'
>>> string_to_dict(s, p)
{'age': '33', 'name': 'dan', 'what': 'developer'}
>>> s = p.format(name='cody', age=18, what='quarterback')
>>> s
'hello, my name is cody and I am a 18 year old quarterback'
>>> string_to_dict(s, p)
{'age': '18', 'name': 'cody', 'what': 'quarterback'}
Run Code Online (Sandbox Code Playgroud)
编辑:另请参阅此答案以获取有关parse和的更多信息parmatter。
pypi 包parse很好地用于此目的:
pip install parse
Run Code Online (Sandbox Code Playgroud)
可以这样使用:
>>> import parse
>>> result=parse.parse('Version {0}.{1}.{2}\n', 'Version 1.15.6\n')
<Result ('1', '15', '6') {}>
>>> values=list(result)
>>> print(values)
['1', '15', '6']
Run Code Online (Sandbox Code Playgroud)
请注意,文档说该parse包默认情况下不会完全模拟格式规范迷你语言;它还使用由re. 特别值得注意的是,s默认情况下这意味着“空白”,而不是str. 通过更改sto的默认类型str(使用extra_types),可以轻松地将其修改为与格式规范一致:
result = parse.parse(format_str, string, extra_types=dict(s=str))
Run Code Online (Sandbox Code Playgroud)
这是string.Formatter使用parse包修改内置类以添加unformat我自己使用的功能的概念性想法:
import parse
from string import Formatter
class Unformatter(Formatter):
'''A parsable formatter.'''
def unformat(self, format, string, extra_types=dict(s=str), evaluate_result=True):
return parse.parse(format, string, extra_types, evaluate_result)
unformat.__doc__ = parse.Parser.parse.__doc__
Run Code Online (Sandbox Code Playgroud)
重要提示:方法名称parse已被Formatter类使用,因此我选择unformat了避免冲突。
更新:您可以像这样使用它 - 与string.Formatter类非常相似。
格式(与 相同'{:d} {:d}'.format(1, 2)):
>>> formatter = Unformatter()
>>> s = formatter.format('{:d} {:d}', 1, 2)
>>> s
'1 2'
Run Code Online (Sandbox Code Playgroud)
取消格式化:
>>> result = formatter.unformat('{:d} {:d}', s)
>>> result
<Result (1, 2) {}>
>>> tuple(result)
(1, 2)
Run Code Online (Sandbox Code Playgroud)
这当然是非常有限的用途,如上所示。但是,我已经提供了一个 pypi 包(parmatter - 一个最初供我自己使用的项目,但也许其他人会发现它有用),它探索了如何将这个想法用于更有用的工作的一些想法。该软件包在很大程度上依赖于上述parse软件包。编辑:在我的带下几年的经验之后,我意识到parmatter(我的第一个包裹!)是一个可怕的、令人尴尬的想法,并已将其删除。
小智 4
实际上,Python 正则表达式库已经提供了您所需的一般功能。您只需稍微更改模式的语法
>>> import re
>>> from operator import itemgetter
>>> mystr='Version 1.15.6\n'
>>> m = re.match('Version (?P<_0>.+)\.(?P<_1>.+)\.(?P<_2>.+)', mystr)
>>> map(itemgetter(1), sorted(m.groupdict().items()))
['1', '15', '6']
Run Code Online (Sandbox Code Playgroud)
如您所见,您必须将(未)格式字符串从 {0} 更改为 (?P<_0>.+)。您甚至可以使用 (?P<_0>\d+) 要求小数。此外,您必须对某些字符进行转义,以防止它们被解释为正则表达式特殊字符。但这又可以再次自动化,例如
>>> re.sub(r'\\{(\d+)\\}', r'(?P<_\1>.+)', re.escape('Version {0}.{1}.{2}'))
'Version\\ (?P<_0>.+)\\.(?P<_1>.+)\\.(?P<_2>.+)'
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
14376 次 |
| 最近记录: |