繁体   English   中英

如何在字符串中找到未转义的单花括号的索引位置?

[英]How do you find the index positions of unescaped single curly braces in a string?

a = "a"
sample_string = "asdf {{a}} {{ { {a} { {a} }"
## need to find these brackets ^     ^     ^
print(sample_string.format(a=a))

上面的字符串将引发

ValueError: unexpected '{' in field name

我希望能够摆脱 _string.formatter_parser 窒息的花括号。 我开始寻找所有不匹配的对,但意识到这不适用于双转义花括号。 我意识到我不知道如何解决这个问题。

## 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

我知道我不能简单地寻找单个牙套而不查看它们是否也配对。 在查看它们是否被转义之前,我不能只查找对。 但是有些情况让我像这样离开:

s1 = f"asdf {{{a}}} {{ {{ {{{a}}} { {a} }"
s2 =  "asdf {{{a}}} {{ {{ {{{a}}} { {a} }"
print(s1)
print(s2.format(a=a))

s1 打印而 s2 不打印。

asdf {a} { { {a} {'a'}
ValueError: unexpected '{' in field name

如何在字符串中找到未转义的花括号的索引位置?


附加信息:

有人问我在这方面做了什么。 现实世界的情况实际上有点尴尬。 正在记录的字符串用 ansi 颜色代码包裹起来,为屏幕上的日志着色,以帮助区分日志行的来源。 同一行也被写入不包含 ansi 代码的日志文件。 为此,将字符串格式化程序大括号条目添加到日志格式化程序执行 format() 的行中,并将大括号替换为 ansi 颜色代码或空字符串。
例子:

"{color.grey}Log entry which {might contain curly} braces in the string {color.reset}"

替换颜色条目的逻辑是使用部分格式化程序完成的,它尝试逐项列出字符串中的所有字段,仅替换传入的字典中存在的字段。除了单例大括号外,它可以完成这项工作。

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 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

用法:

class Color:
    grey = '\033[90m'
    reset = '\033[0m'

colorobj = Color()

try:
    s = partialformat(s, **{"color" : colorobj})
except ValueError as exc:
    pass

输出:

"Log entry which {might contain curly} braces in the string"

或者

"\033[90mLog entry which {might contain curly} braces in the string \033[0m"

附加编辑:

我面临的问题是,当一个字符串包含一个花括号时,我无法在字符串上调用partialformat ,因为它会引发ValueError Exception "Single '{' encountered in format string" 这会导致对日志行着色的能力失败。

s = "{trco.grey}FAILED{trco.r} message {blah blah blah"

我想如果我能检测到它们在字符串中的位置,我可能能够自动转义单例花括号。 事实证明,这比我预期的要困难得多。

另一个编辑:

我相信这是事件顺序的问题。

  1. 原始字符串s = "text with a { single curly brace"
  2. 着色器函数添加了一些基本的花括号文本,稍后将替换"{color.red}text with a { single curly brace{color.reset}""{color.red}text with a { single curly brace{color.reset}"
  3. 在 logging.Formatter.doFormat() 期间用 ansi 颜色代码替换{color.red}

尝试这个:

string = "abcd {{a}} {{{{a}{{a}}"
indices = []
for i, e in enumerate(string):
    if e == '{':
        indices.append(i)
    elif e == '}':
        indices.pop()
print(indices)

这会打印: [11, 12, 13] ,它们是索引

我所做的是遍历字母并只计算打开的大括号,知道最深的大括号首先关闭,然后返回这些打开的大括号的索引

正则表达式适用于这项工作。

>>>import re
>>>t = re.finditer("\s{\s", "asdf {{a}} {{ { {a} { {a} }") 
>>>for a in t:
    print (a.start())
13
19

最初的问题是如何识别不匹配的花括号。 问题是我试图在不可能的时候识别它们。

例子:

有人会说这个中间支架不合适。

"{{a}}{b}}"
     ^

而其他人可能认为最后一个不合适

"{{a}}{b}}"
         ^

仅从文本片段中不可能知道哪个大括号不应该在那里。 因此,我最初的问题并不能完全解决。 在我写这篇文章的时候,我没有意识到我问错了问题。

我的原始问题:如何向记录的文本添加标记,该标记可以稍后格式化(例如在 .doFormat() 日志记录方法期间),它可以替换为 ansi 颜色代码或根据正在处理的格式化程序删除文本?

因此,要记录到屏幕的字符串将包含 ansi 颜色代码,但是当它写入文件 log 时,这些代码将被删除。

就适当的 StackOverflow 礼节而言,我不确定我是否应该完全重新处理我的问题,关闭它,或者只是在这里回答它。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM