파이썬 문자열 리터럴 파싱


9

문제는 파이썬처럼 문자열구문 분석하고 문자열 의 내용을 인쇄하는 것입니다.

  • 입력 (명령 줄 인수 또는 stdin) : 문자열 리터럴 (예 "hello":) (또는 여러 리터럴, 아래의 문자열 리터럴 연결 참조)
  • 출력 (표준 출력) : 문자열의 내용 (예를 들어 hello)

문자열 구문 분석 규칙 :

  • 문자열 리터럴은 작은 따옴표 ( 'a'), 큰 따옴표 ( "a"), 삼중 작은 따옴표 ( '''a''') 또는 삼중 큰 따옴표 ( """a""") 와 일치하는 쌍으로 묶습니다 . 문자열을 연 따옴표 유형의 첫 번째 반복은 문자열을 종료합니다.
  • 백 슬래시 이스케이프 : \' 문자열 내 '에서 \""되고 \\됩니다 \. 다른 백 슬래시 이스케이프를 구현할 필요는 없습니다. 이스케이프 시퀀스의 일부가 아닌 백 슬래시는 백 슬래시를 유지합니다.
  • 문자열 리터럴 연결 : 인접한 문자열 리터럴의 내용이 연결됩니다. 예를 들어 "hello" 'world'됩니다 helloworld.
  • 입력에 리터럴의 일부가 아닌 공백이 포함될 수 있습니다.
  • 리터럴 안팎에서 다른 종류의 공백을 지원할 필요는 없습니다.

추가 규칙 :

  • eval, exec및 이와 유사한 물건은 허용되지 않습니다 리터럴 또는 그 일부를 구문 분석.
  • 입력이 유효하다고 가정 할 수 있습니다.
  • 최대 입력 길이는 1023 자로 가정 할 수 있습니다.

예 :

  • "hello" ' world' -> hello world
  • """\"""'\\\A""" -> """'\\A
  • ( '''"""'''"""'''""" ) (괄호없이, 공백으로)-> """'''

가장 짧은 코드가 승리합니다.


출력물을 저장할 수있는 형식입니까, 아니면 인쇄하여 완료하기에 충분한가요?
DavidC

@David 인쇄하기 만하면됩니다.
flornquake

예를 들어 "\ z"에서 백 슬래시와 z를 출력하려면 코드가 특별히 필요합니까? 그러나 \ '가 큰 따옴표 또는 삼중 따옴표 안에 표시 되어도 아포스트로피가됩니까? 그 맞습니까?
breadbox

@breadbox 정확합니다.
flornquake

코드가 원시 문자열을 지원해야합니까? 그리고 원시가 아닌 문자열과 원시 문자열을 연결하는 것은 어떻습니까?
Bakuriu

답변:


4

펄, 54 자

#!/usr/bin/perl -p
s/ |("""|'''|"|')((\\?.)*?)\1/$2/g;s/\\(["'\\])/$1/g

이 게시물을 게시하는 것과 마찬가지로 Jan Dvorak의 Ruby 솔루션과 거의 동일하다는 것을 알았습니다. 나는 그것이 실제로 얼마나 비슷한 지에 대해 조금 언급하고 있지만, "훌륭한 생각은 비슷하게 생각한다"고 말할 것입니다.

이 프로그램은 Perl 스크립트에서 문자를 계산할 때 이상한 코너 케이스를 강조합니다. 필자가 읽을 때 스크립트에 작은 따옴표가 있으면 -p옵션 을 총계에 대해 두 문자로 계산해야 함을 의미합니다 . 일반적으로 Perl 스크립트 크기를 계산할 때 옵션의 초기 대시 문자 -e는 프로그램을 적절하게 도입하는 것과 함께 묶을 수 있다는 정당성으로 인해 무료로 간주됩니다 ...하지만 추가 탈출을 고려해야합니다 명령 행에 스크립트를 입력해야합니다. 작은 따옴표에는 많은 이스케이프가 필요하므로 그 페널티를 피하기 위해 파일에서 실행되는 스크립트로 계산해야하므로 #!/usr/bin/perl옵션 문자는 무료입니다. 조금 혼란 스럽다.


2
당신이 다르기를 원한다면, (('|")\2{2}?)길이는("""|'''|"|')
Peter Taylor

3

C, 178 자

char*p,*q,b[1024];d;main(t){for(p=q=gets(b);*p=*q++;)
d?*p==92&!(*q-*p&&*q-34&&*q-39)?*p++=*q++:*p-d||t&&*q-d|q[1]-d?++p:
(d=0,q+=2*t):*p-32?d=*p,t=*q==d&q[1]==d,q+=2*t:0;puts(b);}

이것은 삼항 연산자 체인 갱 내부에서 모든 것이 수행되는 C 솔루션 중 하나입니다.

이 프로그램은 문자를 동일한 버퍼로 다시 복사하여 메타 문자를 덮어 쓰는 방식으로 작동합니다. d문자열 내에서 구분 기호를 보유하고 구분 t기호가 삼중 따옴표 인 경우 true입니다.


루프 제어 변수의 조건부 추가 증분을 포함해야한다고 생각합니다. 'foo \\'bar '의 경우 foo \ ar를 제공합니다. 이는 \\를 \로 바꾸는 것처럼 보이지만 새로 입력 한 \로 구문 분석을 계속하고 다음 토큰을 \'로 봅니다.
manatwork

실제로이 예는 유효하지 않은 입력입니다. 'foo\\'문자열 foo \를 참조하고 그 뒤에 공백이나 문자열 분리 문자가 아닌 문자가옵니다.
breadbox

죄송합니다. 나는 그 규칙을 잘못 읽었다. 물론 코드가 정확합니다.
manatwork

3

루비, 74 73 자

puts gets.gsub(/('''|"""|'|")((\\?.)*?)\1|./,'\2').gsub /\\([\\'"])/,'\1'

여기서 핵심은 두 개의 정규 표현식입니다. 첫 번째 정규 표현식은 문자열 경계를 결정하고 내용 만 선택합니다. 문자열 내부가 아닌 모든 것을 제거하고 닫히지 않은 문자열도 삭제합니다.백 슬래시는 possesive-optional 다음에 오는 것으로 취급됩니다. 그러므로,정규식 엔진은 (\\?.)유효한 입력 을 위해 역 추적하지 않기 때문에 (@breadbox 덕분에) 유일한 백 슬래시는 거기에 일치 할 수 없습니다. 따옴표는 지연 반복을 통해 처리됩니다. 두 번째 정규 표현식은 이스케이프 가능한 각 문자 앞에 백 슬래시를 제거합니다. 정규식은 항상 가장 왼쪽의 대안을 먼저 선택하기 위해 엔진에 의존합니다.

또한 상태 머신 접근 방식을 고려했지만 정규식 솔루션에 비해 상당히 큰 상태 (19 상태 x 4 문자 클래스)로 나타났습니다. 누군가 관심이 있다면 여전히 상태 머신을 게시 할 수 있습니다.


이 방법을 사용하는 사소한 결함 : 'foo \\'bar '는'foo \ 'bar'대신 foo \가됩니다.
manatwork

@manatwork 형식에서 무언가를 잃어버린 경우가 아니라면 이것은 정확합니다. 첫 번째 백 슬래시는 두 번째 백 슬래시를 이스케이프합니다. 'foo\\'첫 번째 문자열이며 bar'입력이 문자열 컨텍스트 외부에 있음'foo\\'bar'
John Dvorak

죄송합니다. 내가 어떻게 계산했는지 모르겠다. 물론 맞습니다. 죄송합니다.
manatwork

이것을 실행하려고하면 "regted *? + in regexp"라는 오류 메시지가 나타납니다. 필요한 최소 버전 또는 런타임 플래그가 있습니까?
breadbox

@ breadbox 다른 버전을 확인하지는 않았지만 루비 1.9.3 (JRuby 1.7.2)을 실행하고 있습니다. 적어도 1.9.3을 가정하고 편집해야합니까?
John Dvorak
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.