编写一个程序,以防括号在空格导致停滞的情况下用空格替换


17

您是项目经理。有一天,您的一名程序员发疯了(不是您的错),并在代码库中提取了所有表达式,并在其中添加了随机括号,然后当场退出,对您的不称职(也不是您的错)表示愤慨。这将是一个简单的修复,但是由于某种原因,您没有使用修订控制(完全不是您的错)。出于某种原因,其他程序员都不想遍历每个表达式来修正不匹配的括号(顺便说一句,这不是您的错)。这些天的程序员,您自己想。您将必须自己做。惊恐的事件!这样的任务本该在你下面...

输入将是一行,其中将包含多个左括号(( [ {)和右括号() ] })。它还可能但不总是包含注释(/* */)和字符串文字(" "' ')以及各种数字,字母或符号。

至少会有一个括号(在注释或字符串文字之外)没有相反的对应关系(在注释或字符串文字之外)。例如,}没有{先验的错误。另一个例子:一个(没有)事后的。您的程序将以空格替换使括号匹配所需的最小括号数。

例子:

(4 + (2 + 3))]==> (4 + (2 + 3)) (末尾方括号)
][][[]]==> [][[]](开始方括号)
("Hel(o!"))==> ("Hel(o!") (末尾括号)
( /* )]*/==> /* )]*/ (末尾括号)
{()]==> () (大括号和方括号)

  • 可以从最方便的方式(STDIN,命令行参数,从文件读取等)获取输入。
  • 如果使用相同的清除次数来解决不匹配问题的方法不止一种,则可以接受。
  • 括号中只会有不匹配的内容。字符串文字和注释将始终正确形成。
  • 标题来自此SO线程
  • 注释中永远不会有任何报价,报价中的报价,注释中的注释或报价中的注释。

这是代码高尔夫,因此最少的字节数获胜。如果规范不明确,请在注释中提出问题。


糟糕,我们的编辑在那儿相撞了。:P现在应该修复所有问题。
门把手

@Doorknob顺便说一句,谢谢你。不知道如何从抹空间停止SE。
苦艾酒

我们是否必须处理字符串文字中的转义内容(例如("foo (\") bar"))?
门把手

1
我认为正确的输出{{(})应该是{ } 或相等的,因为开头的情况意味着代码从头开始工作,并且{(})在我所知道的每种编程语言中都被视为不匹配的括号(即“导致停滞”)。但是,那时我已经写了一个答案,所以我有偏见。
DLosc

3
我知道了。猜猜我还不够胜任。;)
DLosc 2014年

Answers:


6

Ruby,223个字符

这个结果有点长。

u,b,i=[],[[],[],[]],-1
s=gets.gsub(/(\/\*|"|').*?(\*\/|"|')|~/){|m|u+=[m];?~}
s.chars{|c|i+=1
(t='{[('.index(c))?b[t].push(i):((t='}])'.index(c))&&(b[t].pop||s[i]=' '))}
b.flatten.map{|l|s[l]=' '}
puts s.gsub(/~/){u.shift}

它的作用是先删除字符串和注释,这样就不会计数(并将它们放回去)。

然后,它逐个字符地经过字符串。找到开口撑杆时,将存储其位置。当找到闭合支架时,它将从其各自的开口支架存储阵列中弹出。

如果pop返回nil(即没有足够的开括号),它将删除闭括号。完成这整个过程后,它将删除其余的多余的开括号(即,没有足够的闭括号)。

在程序结束时,它将所有字符串和注释放回并输出。

取消高尔夫:

in_str = gets

# grab strings and comments before doing the replacements
i, unparsed = 0, []
in_str.gsub!(/(\/\*|"|').*?(\*\/|"|')|\d/){|match| unparsed.push match; i += 1 }

# replaces with spaces the braces in cases where braces in places cause stasis
brace_locations = [[], [], []]
in_str.each_char.with_index do |chr, idx|
    if brace_type = '{[('.index(chr)
        brace_locations[brace_type].push idx
    elsif brace_type = '}])'.index(chr)
        if brace_locations[brace_type].length == 0
            in_str[idx] = ' '
        else
            brace_locations[brace_type].pop
        end
    end
end
brace_locations.flatten.each{|brace_location| in_str[brace_location] = ' ' }

# put the strings and comments back and print
in_str.gsub!(/\d+/){|num| unparsed[num.to_i - 1] }
puts in_str

这是非常令人印象深刻的。但是,有一个问题:它仍然适用于像(("string"/*comment*/)"string"吗?如果我正确地阅读了(非高尔夫版本),则将字符串和注释用unparsed数组中的索引替换,这将导致类似的替换((12)3,然后查找不存在的索引12(或11)。我看到高尔夫球版本仅使用shift,但可能还没有类似的问题吗?
DLosc 2014年

4

Python 3中,410 322 317

import re;a='([{';z=')]}';q=[re.findall('".*?"|/\*.*?\*/|.',input())]
while q:
 t=q.pop(0);s=[];i=0
 for x in t:
  if x in a:s+=[x]
  try:x in z and 1/(a[z.find(x)]==s.pop())
  except:s=0;break
 if[]==s:print(''.join(t));break
 while 1:
  try:
   while t[i]not in a+z:i+=1
  except:break
  u=t[:];u[i]=' ';q+=[u];i+=1

从较小的序列开始,尝试所有可能的缺失集合,直到找到大括号平衡的位置。(我的意思是完全正确地平衡:{{(})产生( ),而不是{(})。)

第一个版本使用了递归生成器函数,该函数确实很酷,但也很长。此版本使用队列执行简单的广度优先搜索。(是的,这是阶乘时间算法。有什么问题?:^ D)


我喜欢这个,因为它实际上找到的删除最少,并且产生正确的嵌套表达式,但是@vonilya的最后评论表明正确的嵌套并不重要。但是,如果需要去除许多牙套,那确实很慢。
rici 2014年

2

C-406

不使用正则表达式的C中的尝试。

#define A if((d==125||d==93||d==41)
char*s;t[256];f(i,m,n,p){while(s[i]!=0){int c=s[i],k=s[i+1],v=1,d;if((c==42&&k==47)||(c==m&&i>n))return i;if(!p||p==2){if((c==39||c==34)||(c==47&&k==42)){i=f(i,c*(c!=47),i,p+1);
c=c==47?42:c;}d=c+1+1*(c>50);A){v=f(i+1,d,i,2);if(!p&&v)t[d]++;if(p==2&&v)i=v;}}d=c;A&&!p){v=!!t[c];t[c]-=v;}if(p<2)putchar(c*!!v+32*!v);i++;}return 0;}main(int c,char*v[]){s=v[1];f(0,0,0,0);}

要编译并运行(在Linux机器上):
gcc -o方括号
brackets.c。/ 方括号“ [(])”

在未定义的情况下,例如[(]),它将返回最后一个有效的括号对()


2

Python 3、320

import re
O=dict(zip('([{',')]}'))
def o(s,r,m=0,t=[]):m+=re.match(r'([^][)({}/"]|/(?!\*)|/\*.*?\*/|".*?")*',s[m:]).end();return r and o(s[:m]+' '+s[m+1:],r-1,m+1,t)or(o(s,r,m+1,t+[O[s[m]]])if s[m]in O else[s[m]]==t[-1:]and o(s,r,m+1,t[:-1]))if s[m:]else not t and s
s=input();i=0;a=0
while not a:a=o(s,i);i+=1
print(a)

像DLosc的解决方案一样,它会调查所有可能的删除,但是它使用了一种递归的浏览和后备策略,该策略快得多。我知道速度并不是代码高尔夫的标准,无论如何穷举搜索都是指数级的,但是这种搜索可以({({({({({({({({(}}}}}}}}在几秒钟内处理输入。


打得好,打得好。我确实设法降到了317,但我认为您应该能够轻松通过该认证。(与此同时,我的程序仍在您的示例输入中搅动……)
DLosc 2014年

@DLosc:不要屏住呼吸:)。我的机器花了58分钟才能完成6个开放式括号的模式版本。为了解决宇宙陷入热死之前的停滞,您需要记住队列;否则,您将得到一个O(n!!)解决方案,而不是O(n!)。(我的高尔夫球场是,O(n*2^n)而不是O(2^n),因为o实际上产生的图案最多可以r去除,而不是精确r去除。易于修复,但是会花费一些字符。)
rici 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.