a = "a"
sample_string = "asdf {{a}} {{ { {a} { {a} }"
## need to find these brackets ^ ^ ^
print(sample_string.format(a=a))
Run Code Online (Sandbox Code Playgroud)
上面的字符串将引发
ValueError: unexpected '{' in field name
Run Code Online (Sandbox Code Playgroud)
我希望能够摆脱令人窒息的大括号_string.formatter_parser。我开始沿着寻找所有不匹配对的道路走下去,但意识到这对于双转义花括号不起作用。我意识到我不知道如何解决这个问题。
ValueError: unexpected '{' in field name
Run Code Online (Sandbox Code Playgroud)
我知道我不能简单地寻找单个牙套而不查看它们是否也配对。我不能在查看它们是否逃脱之前就先寻找它们。但有些情况让我感到困惑,如下所示:
## this does not solve the problem.
def find_unmatched(s):
indices = []
stack = []
indexstack = []
for i, e in enumerate(s):
if e == "{":
stack.append(e)
indexstack.append(i)
elif e == "}":
if len(stack) < 1:
indices.append(i)
else:
stack.pop()
indexstack.pop()
while len(indexstack) > 0:
indices.append(indexstack.pop())
return indices
Run Code Online (Sandbox Code Playgroud)
s1打印而s2没有打印。
asdf {a} { { {a} {'a'}
ValueError: unexpected '{' in field name
Run Code Online (Sandbox Code Playgroud)
如何找到字符串中未转义大括号的索引位置?
附加信息:
有人问我到底用这个做什么。现实世界的情况实际上有点尴尬。正在记录的字符串用 ANSI 颜色代码包裹起来,为屏幕上的日志着色,以帮助区分日志行的来源。同一行也被写入不包含 ANSI 代码的日志文件中。为了实现此目的,将字符串格式化程序大括号条目添加到日志格式化程序执行 format() 的行,并将大括号替换为 ANSI 颜色代码或空字符串。
例子:
s1 = f"asdf {{{a}}} {{ {{ {{{a}}} { {a} }"
s2 = "asdf {{{a}}} {{ {{ {{{a}}} { {a} }"
print(s1)
print(s2.format(a=a))
Run Code Online (Sandbox Code Playgroud)
替换颜色条目的逻辑是使用部分格式化程序完成的,它尝试逐项列出字符串中的所有字段,仅替换传入的字典中存在的字段。它完成除单例花括号之外的工作。
asdf {a} { { {a} {'a'}
ValueError: unexpected '{' in field name
Run Code Online (Sandbox Code Playgroud)
用法:
"{color.grey}Log entry which {might contain curly} braces in the string {color.reset}"
Run Code Online (Sandbox Code Playgroud)
输出:
"Log entry which {might contain curly} braces in the string"
Run Code Online (Sandbox Code Playgroud)
或者
"\033[90mLog entry which {might contain curly} braces in the string \033[0m"
Run Code Online (Sandbox Code Playgroud)
附加编辑:
我面临的问题是,当字符串包含单个大括号时,我无法调用partialformat该字符串,因为它会引发ValueError Exception "Single '{' encountered in format string". 这会导致对日志行进行着色的功能失败。
def partialformat(s: str, recursionlimit: int = 10, **kwargs):
"""
vformat does the actual 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 ValueError as exc:
#if we are ever to auto escape unmatched curly braces, it shall go here.
raise exc
except Exception as exc:
raise exc
return fs
Run Code Online (Sandbox Code Playgroud)
我想如果我能检测到它们在字符串中的位置,我也许能够自动转义单例花括号。事实证明这比我预想的要困难。
另一个编辑:
我认为这是事件顺序的问题。
s = "text with a { single curly brace""{color.red}text with a { single curly brace{color.reset}"logging.Formatter.doFormat()替换。{color.red}最初的问题是如何识别不匹配对的花括号。问题是我试图在不可能的情况下识别它们。
例子:
有人会说这个中间支架不合适。
"{{a}}{b}}"
^
Run Code Online (Sandbox Code Playgroud)
虽然其他人可能认为最后一个不合适
"{{a}}{b}}"
^
Run Code Online (Sandbox Code Playgroud)
仅从文本片段中不可能知道哪个大括号不应该在那里。因此,我原来的问题无法完全解决。当我写这篇文章时,我没有意识到我问了错误的问题。
我原来的问题:如何将标记添加到记录的文本中,该标记可以稍后格式化(例如在记录的 .doFormat() 方法期间),可以用 ansi 颜色代码替换或删除,具体取决于哪个格式化程序正在处理文本?
因此,要记录到屏幕的字符串将包含 ansi 颜色代码,但是当将其写入文件日志时,这些代码将被删除。
就正确的 StackOverflow 礼仪而言,我不确定我是否应该彻底修改我的问题,关闭它,或者只是在这里回答它。