파이썬 문자열 리터럴 파싱


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.