Algorithm 查找字符串中不平衡括号的算法

Algorithm 查找字符串中不平衡括号的算法,algorithm,parsing,Algorithm,Parsing,PostScript/PDF字符串文字由括号包围,只要括号完全平衡,就允许包含未转义的括号。比如说 ( () ) % valid string constant ( ( ) % invalid string constant, the inner ( should be escaped 我知道一种算法,可以告诉我字符串中是否有不平衡的括号;我要寻找的是一种算法,它可以找到一组最小的不平衡括号,这样我就可以在括号前面加反斜杠,使整个字符串成为有效的文本。更多示例: ( ⟶ \(

PostScript/PDF字符串文字由括号包围,只要括号完全平衡,就允许包含未转义的括号。比如说

( () )  % valid string constant
( ( )   % invalid string constant, the inner ( should be escaped
我知道一种算法,可以告诉我字符串中是否有不平衡的括号;我要寻找的是一种算法,它可以找到一组最小的不平衡括号,这样我就可以在括号前面加反斜杠,使整个字符串成为有效的文本。更多示例:

(     ⟶   \(
()    ⟶   ()
(()   ⟶   \(() or (\()
())   ⟶   ()\) or (\))
()(   ⟶   ()\(

对标准的基于堆栈的算法进行修改以检测不平衡的括号应该适合您。下面是一些伪代码:

void find_unbalaned_indices(string input)
{
    // initialize 'stack' containing of ints representing index at
    // which a lparen ( was seen

    stack<int index> = NIL          

    for (i=0 to input.size())
    {
        // Lparen. push into the stack
        if (input[i] == '(')
        {
            // saw ( at index=i
            stack.push(i);
        }
        else if (input[i] == ')')
        {
           out = stack.pop();
           if (out == NIL)
           {
               // stack was empty. Imbalanced RParen.
               // index=i needs to be escaped
               ... 
           }  
           // otherwise, this rparen has a balanced lparen.
           // nothing to do.
        }
    }

    // check if we have any imbalanced lparens
    while (stack.size() != 0)
    {
        out = stack.pop();
        // out is imbalanced
        // index = out.index needs to be escaped.
    }
}
void查找不平衡索引(字符串输入)
{
//初始化包含表示索引的整数的“堆栈”
//这是一个lparen(被看到的
堆栈=零
对于(i=0到input.size())
{
//Lparen。推入堆栈
如果(输入[i]=='(')
{
//锯(在指数=i时)
堆栈推送(i);
}
else if(输入[i]=')')
{
out=stack.pop();
如果(out==NIL)
{
//堆栈为空。RParen不平衡。
//index=i需要转义
... 
}  
//否则,此rparen具有平衡的lparen。
//无事可做。
}
}
//检查是否有不平衡的LPAREN
while(stack.size()!=0)
{
out=stack.pop();
//这是不平衡的
//index=out.index需要转义。
}
}

希望这能有所帮助。

有没有代码示例的首选语言?输入字符串有多大?这个项目目前使用的是Python;第二个首选是C-family。不过,如果您碰巧需要使用其他语言,我可能可以处理(除非它是一种专门编写的语言)。我认为字符串的长度可能不会超过几百字节。您可能会在编译器错误恢复/更正中发现一些有用的东西。但这是一个难题。您能否强调一个特定的情况,在这种情况下会失败?我的想法是,我不能比O(N)(字符串长度)更快。我必须至少读一次字符。这对我来说很好。它将跳过保持平衡所需的最近括号,这是一个很好的选择。@Sanjit:问题不在于算法“失败”或者说它很慢,问题是错误恢复很困难,因为它意味着试图假定用户的意图,而您的算法并不试图这样做。考虑一个“真实”的情况,而不是简单地关注一串括号。
含糊不清地说些什么(例如考虑xx或yy(特别是对于case foo)
。在这里,您的算法建议转义第一个
),而转义“显而易见”人类阅读器的解决方案是在末尾添加一个r括号。@Matthieu:这是一个明确的优化问题,我们要做的就是通过省略尽可能多的反斜杠来尽可能有效地压缩。据我所知,生成的字符串是否“易于阅读”并不重要。我相信marcog的意思是Sanjit的策略有时会产生非最小的结果(顺便说一句,我认为这是一个不正确的说法,尽管我无法证明)。@j_random_hacker:鉴于marcog之前对错误恢复的评论,我确实认为他是指“工作非常好”的错误恢复而不是优化。我也认为Sanjit的策略非常适合于在不考虑实际意义的情况下纯粹平衡括号,我需要考虑一些非最小结果,因为我似乎无法在头脑中产生一个示例。这似乎可行,但我觉得我不理解。你能解释一下吗逻辑并做一个参数(我不需要正式的证明),它添加了最小数量的反斜杠?a')必须在没有匹配的情况下转义('s在其左边。escape_oneway()非常直接地表达了这一点。通过对称,a'('必须在没有匹配的情况下转义)通过反转字符串并交换对“(”和“)的检查,我们将其简化为第一种情况’。有一个最终的反转来撤销这个反转。我当时确信第二次越位不会影响第一次越位时做出的任何决定,但我不知道为什么,现在我需要退出。也许我错了。这可能很正确,但我认为你的推理有一个漏洞:什么是“匹配”(‘完全正确?可能有多个’(‘可能与给定的’)匹配),所以您需要确定我认为是哪一个。如果是‘匹配’(‘您的意思是’(‘可能匹配’),您的初始语句是不正确的——请看
())
。必须转义其中一个’。两个都可以。
def escape(s):
    return ''.join(r(')(', r('()', s)))

def r(parens, chars):
    return reversed(list(escape_oneway(parens, chars)))

def escape_oneway(parens, chars):
    """Given a sequence of characters (possibly already escaped),
    escape those close-parens without a matching open-paren."""
    depth = 0
    for x in chars:
        if x == parens[0]:
            depth += 1
        if x == parens[1]:
            if depth == 0:
                yield '\\' + x
                continue
            else:
                depth -= 1
        yield x