转义字符串中的大括号以进行未定义次数的格式化
Escaping curly braces in string to be formatted an undefined number of times
相关:
-
-
您使用花括号 ({•••}
) 来表示要格式化的字符串部分。如果您想使用文字大括号字符以便 .format()
忽略它们,您可以使用双大括号 ({{•••}}
)。 MCVE:
string = "{format} {{This part won't be formatted. The final string will have literal curly braces here.}}"
print string.format(format='string')
如果您有一串 .format()
,则每次使用 .format()
时大括号的数量都会加倍。最后一个由 4 个大括号包围,并在最终输出中以文字花括号结束。 MCVE:
string = "{format1} {{format2}} {{{{3rd one won't be formatted. The final string will have literal curly braces here.}}}}"
print string.format(format1='string1').format(format2='string2')
也可以将另一个格式字符串格式化为一个格式字符串。最后一个由 4 个大括号包围,并在最终输出中以文字花括号结束。 MCVE:
string = "{format1} {{{{3rd one won't be formatted. The final string will have literal curly braces here.}}}}"
print string.format(format1='{format2}').format(format2='string')
当您根据运行时确定的条件使用 .format()
链时会出现问题。如果您希望将一组花括号作为文字字符进行转义,您使用多少个? MCVE:
string = "{} {{{{{{Here I don't know exactly how many curly braces to use because this string is formatted differently due to conditions that I have no control over.}}}}}}"
if fooCondition:
string = string.format('{} bar')
if barCondition:
string = string.format('{} baz')
if bazCondition:
string = string.format('{} buzz')
string = string.format('foo')
print string
字符串的第一部分有 4 个可能的输出:
foo
foo bar
foo baz bar
foo buzz baz bar
字符串的第二部分以不同数量的大括号结束,具体取决于条件的数量 True
。我希望第二部分的花括号保持永久转义,比如 每次调用 .format()
时都不会“掉一层”。 我可以这样解决问题,MCVE:
string = "{} {{DRY - Don't repeat yourself!}}"
if fooCondition:
string = string.format('{} bar').replace("{DRY - Don't repeat yourself!}", "{{DRY - Don't repeat yourself!}}")
if barCondition:
string = string.format('{} baz').replace("{DRY - Don't repeat yourself!}", "{{DRY - Don't repeat yourself!}}")
if bazCondition:
string = string.format('{} buzz').replace("{DRY - Don't repeat yourself!}", "{{DRY - Don't repeat yourself!}}")
string = string.format('foo')
print string
But that's duplicate code (bad practice).
MCVE 不是我的真实代码。我的真实代码在 Google App Engine 网络服务器上运行。它又长又复杂。我在字符串中使用 HTML、CSS 和 JavaScript。我想通过 .format()
将内容插入 HTML 而不会弄乱 CSS 和 JS 的花括号。我当前的实现是不可扩展的并且非常容易出错。我必须管理最多 5 个连续的花括号(像这样: {{{{{•••}}}}}
)才能不受影响地通过 .format()
链。我需要定期将大括号重新插入到未格式化固定次数的字符串中。修复这个意大利面条代码的优雅方法是什么?
如何在 Python 格式字符串中永久转义花括号?
简单明了的解决方案是,不要将 .format()
应用于您无法完全控制的字符串。相反,也许做
result = thestring.replace('{postURL}', url).replace('{postTitle}', title)
我整理了一个部分格式函数(在 python3.x 中),它覆盖了字符串格式化方法,允许您仅格式化字符串中需要格式化的部分。编辑:我也包含了一个 python 2 版本。
## python 3x version
import string
from _string import formatter_field_name_split
################################################################################
def partialformat(s: str, recursionlimit: int = 10, **kwargs):
"""
vformat does the acutal work of formatting strings. _vformat is the
internal call to vformat and has the ability to alter the recursion
limit of how many embedded curly braces to handle. But for some reason
vformat does not. vformat also sets the limit to 2!
The 2nd argument of _vformat 'args' allows us to pass in a string which
contains an empty curly brace set and ignore them.
"""
class FormatPlaceholder(object):
def __init__(self, key):
self.key = key
def __format__(self, spec):
result = self.key
if spec:
result += ":" + spec
return "{" + result + "}"
def __getitem__(self, item):
return
class FormatDict(dict):
def __missing__(self, key):
return FormatPlaceholder(key)
class PartialFormatter(string.Formatter):
def get_field(self, field_name, args, kwargs):
try:
obj, first = super(PartialFormatter, self).get_field(field_name, args, kwargs)
except (IndexError, KeyError, AttributeError):
first, rest = formatter_field_name_split(field_name)
obj = '{' + field_name + '}'
# loop through the rest of the field_name, doing
# getattr or getitem as needed
for is_attr, i in rest:
if is_attr:
try:
obj = getattr(obj, i)
except AttributeError as exc:
pass
else:
obj = obj[i]
return obj, first
fmttr = PartialFormatter()
try:
fs, _ = fmttr._vformat(s, ("{}",), FormatDict(**kwargs), set(), recursionlimit)
except Exception as exc:
raise exc
return fs
编辑:看起来像 python 2.x 有一些细微差别。
## python 2.x version
import string
formatter_field_name_split = str._formatter_field_name_split
def partialformat(s, recursionlimit = 10, **kwargs):
"""
vformat does the acutal work of formatting strings. _vformat is the
internal call to vformat and has the ability to alter the recursion
limit of how many embedded curly braces to handle. But for some reason
vformat does not. vformat also sets the limit to 2!
The 2nd argument of _vformat 'args' allows us to pass in a string which
contains an empty curly brace set and ignore them.
"""
class FormatPlaceholder(object):
def __init__(self, key):
self.key = key
def __format__(self, spec):
result = self.key
if spec:
result += ":" + spec
return "{" + result + "}"
def __getitem__(self, item):
return
class FormatDict(dict):
def __missing__(self, key):
return FormatPlaceholder(key)
class PartialFormatter(string.Formatter):
def get_field(self, field_name, args, kwargs):
try:
obj, first = super(PartialFormatter, self).get_field(field_name, args, kwargs)
except (IndexError, KeyError, AttributeError):
first, rest = formatter_field_name_split(field_name)
obj = '{' + field_name + '}'
# loop through the rest of the field_name, doing
# getattr or getitem as needed
for is_attr, i in rest:
if is_attr:
try:
obj = getattr(obj, i)
except AttributeError as exc:
pass
else:
obj = obj[i]
return obj, first
fmttr = PartialFormatter()
try:
fs = fmttr._vformat(s, ("{}",), FormatDict(**kwargs), set(), recursionlimit)
except Exception as exc:
raise exc
return fs
用法:
class ColorObj(object):
blue = "^BLUE^"
s = '{"a": {"b": {"c": {"d" : {} {foo:<12} & {foo!r} {arg} {color.blue:<10} {color.pink} {blah.atr} }}}}'
print(partialformat(s, foo="Fooolery", arg="ARRrrrrrg!", color=ColorObj))
输出:
{"a": {"b": {"c": {"d" : {} Fooolery & 'Fooolery' Fooolery ARRrrrrrg! ^BLUE^ {color.pink} {blah.atr} }}}}
我的解决方案:
我将字符串中的 "permanent" 花括号替换为模糊的 Unicode 字符,我确信我永远不会将其用于任何其他目的。
例如:
我输入“⁍”表示“{”
我输入“⁌”表示“}”
完成所有格式设置后,我用相应的大括号替换每个替换字符。
stringAfterFormatting.replace("⁍", "{").replace("⁌", "}")
我在字符串上使用链式和嵌套式 .format()
多少次都没有关系。
string.format(•••).format(•••).format(•••).replace("⁍", "{").replace("⁌", "}")
我格式化我需要格式化的,.replace()
最后的花括号。
相关:
您使用花括号 ({•••}
) 来表示要格式化的字符串部分。如果您想使用文字大括号字符以便 .format()
忽略它们,您可以使用双大括号 ({{•••}}
)。 MCVE:
string = "{format} {{This part won't be formatted. The final string will have literal curly braces here.}}"
print string.format(format='string')
如果您有一串 .format()
,则每次使用 .format()
时大括号的数量都会加倍。最后一个由 4 个大括号包围,并在最终输出中以文字花括号结束。 MCVE:
string = "{format1} {{format2}} {{{{3rd one won't be formatted. The final string will have literal curly braces here.}}}}"
print string.format(format1='string1').format(format2='string2')
也可以将另一个格式字符串格式化为一个格式字符串。最后一个由 4 个大括号包围,并在最终输出中以文字花括号结束。 MCVE:
string = "{format1} {{{{3rd one won't be formatted. The final string will have literal curly braces here.}}}}"
print string.format(format1='{format2}').format(format2='string')
当您根据运行时确定的条件使用 .format()
链时会出现问题。如果您希望将一组花括号作为文字字符进行转义,您使用多少个? MCVE:
string = "{} {{{{{{Here I don't know exactly how many curly braces to use because this string is formatted differently due to conditions that I have no control over.}}}}}}"
if fooCondition:
string = string.format('{} bar')
if barCondition:
string = string.format('{} baz')
if bazCondition:
string = string.format('{} buzz')
string = string.format('foo')
print string
字符串的第一部分有 4 个可能的输出:
foo
foo bar
foo baz bar
foo buzz baz bar
字符串的第二部分以不同数量的大括号结束,具体取决于条件的数量 True
。我希望第二部分的花括号保持永久转义,比如 每次调用 .format()
时都不会“掉一层”。 我可以这样解决问题,MCVE:
string = "{} {{DRY - Don't repeat yourself!}}"
if fooCondition:
string = string.format('{} bar').replace("{DRY - Don't repeat yourself!}", "{{DRY - Don't repeat yourself!}}")
if barCondition:
string = string.format('{} baz').replace("{DRY - Don't repeat yourself!}", "{{DRY - Don't repeat yourself!}}")
if bazCondition:
string = string.format('{} buzz').replace("{DRY - Don't repeat yourself!}", "{{DRY - Don't repeat yourself!}}")
string = string.format('foo')
print string
But that's duplicate code (bad practice).
MCVE 不是我的真实代码。我的真实代码在 Google App Engine 网络服务器上运行。它又长又复杂。我在字符串中使用 HTML、CSS 和 JavaScript。我想通过 .format()
将内容插入 HTML 而不会弄乱 CSS 和 JS 的花括号。我当前的实现是不可扩展的并且非常容易出错。我必须管理最多 5 个连续的花括号(像这样: {{{{{•••}}}}}
)才能不受影响地通过 .format()
链。我需要定期将大括号重新插入到未格式化固定次数的字符串中。修复这个意大利面条代码的优雅方法是什么?
如何在 Python 格式字符串中永久转义花括号?
简单明了的解决方案是,不要将 .format()
应用于您无法完全控制的字符串。相反,也许做
result = thestring.replace('{postURL}', url).replace('{postTitle}', title)
我整理了一个部分格式函数(在 python3.x 中),它覆盖了字符串格式化方法,允许您仅格式化字符串中需要格式化的部分。编辑:我也包含了一个 python 2 版本。
## python 3x version
import string
from _string import formatter_field_name_split
################################################################################
def partialformat(s: str, recursionlimit: int = 10, **kwargs):
"""
vformat does the acutal work of formatting strings. _vformat is the
internal call to vformat and has the ability to alter the recursion
limit of how many embedded curly braces to handle. But for some reason
vformat does not. vformat also sets the limit to 2!
The 2nd argument of _vformat 'args' allows us to pass in a string which
contains an empty curly brace set and ignore them.
"""
class FormatPlaceholder(object):
def __init__(self, key):
self.key = key
def __format__(self, spec):
result = self.key
if spec:
result += ":" + spec
return "{" + result + "}"
def __getitem__(self, item):
return
class FormatDict(dict):
def __missing__(self, key):
return FormatPlaceholder(key)
class PartialFormatter(string.Formatter):
def get_field(self, field_name, args, kwargs):
try:
obj, first = super(PartialFormatter, self).get_field(field_name, args, kwargs)
except (IndexError, KeyError, AttributeError):
first, rest = formatter_field_name_split(field_name)
obj = '{' + field_name + '}'
# loop through the rest of the field_name, doing
# getattr or getitem as needed
for is_attr, i in rest:
if is_attr:
try:
obj = getattr(obj, i)
except AttributeError as exc:
pass
else:
obj = obj[i]
return obj, first
fmttr = PartialFormatter()
try:
fs, _ = fmttr._vformat(s, ("{}",), FormatDict(**kwargs), set(), recursionlimit)
except Exception as exc:
raise exc
return fs
编辑:看起来像 python 2.x 有一些细微差别。
## python 2.x version
import string
formatter_field_name_split = str._formatter_field_name_split
def partialformat(s, recursionlimit = 10, **kwargs):
"""
vformat does the acutal work of formatting strings. _vformat is the
internal call to vformat and has the ability to alter the recursion
limit of how many embedded curly braces to handle. But for some reason
vformat does not. vformat also sets the limit to 2!
The 2nd argument of _vformat 'args' allows us to pass in a string which
contains an empty curly brace set and ignore them.
"""
class FormatPlaceholder(object):
def __init__(self, key):
self.key = key
def __format__(self, spec):
result = self.key
if spec:
result += ":" + spec
return "{" + result + "}"
def __getitem__(self, item):
return
class FormatDict(dict):
def __missing__(self, key):
return FormatPlaceholder(key)
class PartialFormatter(string.Formatter):
def get_field(self, field_name, args, kwargs):
try:
obj, first = super(PartialFormatter, self).get_field(field_name, args, kwargs)
except (IndexError, KeyError, AttributeError):
first, rest = formatter_field_name_split(field_name)
obj = '{' + field_name + '}'
# loop through the rest of the field_name, doing
# getattr or getitem as needed
for is_attr, i in rest:
if is_attr:
try:
obj = getattr(obj, i)
except AttributeError as exc:
pass
else:
obj = obj[i]
return obj, first
fmttr = PartialFormatter()
try:
fs = fmttr._vformat(s, ("{}",), FormatDict(**kwargs), set(), recursionlimit)
except Exception as exc:
raise exc
return fs
用法:
class ColorObj(object):
blue = "^BLUE^"
s = '{"a": {"b": {"c": {"d" : {} {foo:<12} & {foo!r} {arg} {color.blue:<10} {color.pink} {blah.atr} }}}}'
print(partialformat(s, foo="Fooolery", arg="ARRrrrrrg!", color=ColorObj))
输出:
{"a": {"b": {"c": {"d" : {} Fooolery & 'Fooolery' Fooolery ARRrrrrrg! ^BLUE^ {color.pink} {blah.atr} }}}}
我的解决方案:
我将字符串中的 "permanent" 花括号替换为模糊的 Unicode 字符,我确信我永远不会将其用于任何其他目的。
例如:
我输入“⁍”表示“{”
我输入“⁌”表示“}”
完成所有格式设置后,我用相应的大括号替换每个替换字符。
stringAfterFormatting.replace("⁍", "{").replace("⁌", "}")
我在字符串上使用链式和嵌套式 .format()
多少次都没有关系。
string.format(•••).format(•••).format(•••).replace("⁍", "{").replace("⁌", "}")
我格式化我需要格式化的,.replace()
最后的花括号。