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