괄호가 정체를 일으키는 경우 괄호를 공백으로 대체하는 프로그램을 작성하십시오.


17

프로젝트 관리자입니다. 어느 날, 프로그래머 중 하나는 미친 갔다 ( 하지 당신의 잘못 )과 무능력 (대한 불평, 그 자리에서 종료하기 전에, 그들에게 무작위 브래킷을 코드베이스에 모두에게 표현했다 및 추가 도없는 당신의 잘못 ). 그러나 이것은 어떤 이유로 수정 제어를 사용하지 않는 이유입니다 ( 전적으로 귀하의 결함이 아닙니다 ). 그리고 어떤 이유로 든 다른 프로그래머 중 어느 것도 일치하지 않는 대괄호를 고치기 위해 모든 표현을 거치기를 원하지 않습니다 . 요즘 프로그래머 여러분은 스스로 생각합니다. 직접해야합니다. 공포! 그런 일은 당신의 아래에 있어야 했어요 ...

입력은 단일 행이되며 여기에는 많은 왼쪽 대괄호 ( ( [ {)와 오른쪽 대괄호 ( ) ] })가 포함됩니다. 또한 주석 ( /* */) 및 문자열 리터럴 ( " "또는 ' ')과 다양한 숫자, 문자 또는 기호를 포함 할 수도 있지만 항상 그런 것은 아닙니다 .

대응하는 반대 (주석 또는 문자열 리터럴 제외)가없는 하나 이상의 대괄호 (주석 또는 문자열 리터럴 제외)가 있습니다. 예를 들어, 사전이 }없는 오류 {. 또 다른 예 : 나중에 (는없는 a ). 프로그램은 대괄호를 일치시키는 데 필요한 최소 대괄호 수를 공백으로 대체합니다.

예 :

(4 + (2 + 3))]==> (4 + (2 + 3)) (끝에서 대괄호)
][][[]]==> [][[]](시작에서 대괄호)
("Hel(o!"))==> ("Hel(o!") (끝 괄호)
( /* )]*/==> /* )]*/ (시작에서 괄호)
{()]==> () (곱슬 브래킷 대괄호)

  • 가장 편리한 방법 (STDIN, 명령 행 인수, 파일 읽기 등)에서 입력을 가져올 수 있습니다.
  • 동일한 제거 횟수로 불일치를 해결하는 방법이 두 가지 이상인 경우 둘 중 하나를 사용할 수 있습니다.
  • 대괄호에는 불일치 만 있습니다. 문자열 리터럴과 주석은 항상 올바르게 구성됩니다.
  • 제목은 이 SO 스레드 에서 나옵니다.
  • 주석에는 인용 부호, 인용 부호에는 인용 부호, 주석에는 주석 또는 인용 부호에는 포함되지 않습니다.

이것은 코드 골프이므로 최소 바이트 수가 이깁니다. 사양이 명확하지 않은 경우 의견에 질문하십시오.


우리 편집 내용이 충돌했습니다. : P 이제 모든 것이 고쳐 져야합니다.
Doorknob

@Doorknob 그건 그렇고, 고마워. 공간을 닦아에서 SE를 중지하는 방법을 몰랐다.
압생트

문자열 리터럴에서 이스케이프 처리를 처리해야 ("foo (\") bar")합니까 (예 :) ?
손잡이

1
시작 시나리오에서 코드가 시작되는 것을 암시하고 내가 알고있는 모든 프로그래밍 언어에서 불일치 한 괄호로 계산되기 때문에 (예 : "정지 원인"??) 올바른 출력이 같거나 {{(})같아야 한다고 주장합니다 . 그러나 나는 이미 답을 썼기 때문에 편견이 있습니다. { } {(})
DLosc

3
내가 참조. 내가 무능하지 않은 것 같아 ;)
DLosc

답변:


6

루비, 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

4

파이썬 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

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);}

리눅스 머신에서 컴파일하고 실행하기 :
gcc -o brackets brackets.c
./brackets "[(])"

[(])와 같이 정의되지 않은 경우 마지막 유효한 대괄호 쌍 ()을 반환합니다.


2

파이썬 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

@DLosc : 숨을 참지 마십시오 :). 6 개의 열린 Parens로 해당 패턴의 버전을 만드는 데 58 분이 걸렸습니다. 우주가 열사병에 도달하기 전에 정체 상태를 해결하려면 대기열을 메모해야합니다. 그렇지 않으면 결국 O(n!!)솔루션이 아닙니다 O(n!). ( 실제로 정확한 제거 대신 최대 제거 까지 모든 패턴을 생성 하기 때문에 내 골프는 O(n*2^n)대신에 사용됩니다 . 수정하기 쉽지만 몇 자의 비용이 듭니다.)O(2^n)orr
rici
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.