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