삼항 연산자의 표현 평가


29

알파벳을 통해 문법을 고려 { 0, 1, ?, :} 에 의해 정의 된 생산 규칙

S → 010 ?:의 ┃ 1 ?:

s 에서 생성 된 문자열 ?:이 있으면 오른쪽 연관 (예 : a?B?X:Y:c?d:e?f:gmeans a?(B?X:Y):(c?d:(e?f:g))) 인 표현식으로 구문 분석 하고 다음 시맨틱으로 평가하십시오.

eval(0) = 0
eval(1) = 1
eval(0?a:b) = eval(b)
eval(1?a:b) = eval(a)

결과가 0 이면 고정 값을 출력하십시오. 출력이 1 이면 다른 고정 값을 출력하십시오. 답에 선택한 출력 값 (예 : 0/ 1또는 False/ True)을 지정하십시오.

테스트 사례

0 -> 0
1 -> 1
0?0:1 -> 1
0?1:0 -> 0
1?0:1 -> 0
1?1:0 -> 1
0?1?0:1:1 -> 1
1?0?1:1:1 -> 1
1?0:1?0:1?1:1 -> 0
1?1?1:0?1?0:0:0:0 -> 1
1?0:1?0?1:1?1:0:1?1?1:1:1?0:1 -> 0
1?1?1:0?0?1:1:0?1:0:1?1?0?0:0:1?1:0:0?1?0:1:1?0:1 -> 1
0?0?1?0?0:1:0?0:0:0?0?1:1:1?0:1:0?0?0?1:0:0?1:1:1?1?0:1:1 -> 0

규칙

  • 문자열을 일부 프로그래밍 언어 에서 코드로 해석 하여 실행 하는 언어 내장 기능을 사용하지 않을 수 있습니다 (예 : JavaScript / Perl / Ruby / Python 's eval).
  • 즉, 코드는 실제로 입력 문자열을 구문 분석 한 다음 평가할 필요 가 없습니다 . 동등한 결과를 달성하고 이전 규칙을 위반하지 않는 접근 방식을 취할 수 있습니다.
  • 프로그램이에 대해 점검 perl -le 'print eval<>'됩니다.
  • 가장 짧은 코드 (바이트)가 이깁니다.

문자열을 근본적으로 변경 한 후 문자열을 $ my_language 코드로 해석하는 eval과 같은 언어 내장 기능을 사용하는 것은 어떻습니까?
Adám

문자열을 $ some_other_language 코드 로 해석하는 내장은 어떻습니까?
Mego

@ Adám 죄송합니다.
Lynn

@ Mego 흠, 거기에 사소한 부정 행위의 기회가 있으므로, 그런 모든 내장을 다루기 위해 규칙을 확장했습니다.
Lynn

1
마틴의 테스트 케이스의 관점에서, 아마도는 문법을 정의하는 것이 더 간단 할 것 S → T | T ? S : S, T → 0 | 1연관성에 대해 이야기 할 필요를 제거하는?
피터 테일러

답변:



17

망막 , 23 바이트

r-1=+`0\?.:|1\?(.):.
$1

온라인으로 사용해보십시오! 첫 번째 줄은 줄 바꿈으로 구분 된 테스트 스위트를 활성화합니다.

설명

실제로는 매우 간단합니다. +리터럴 만 포함 된 삼항을 반복적으로 평가 하여 입력을 결과로 줄입니다. 이 작업이 오른쪽으로 수행되도록 오른쪽에서 왼쪽으로 일치하는 항목을 찾습니다 (r 으로 일치하는 항목을 찾고 () 마지막으로 찾은 일치 항목 만 바꿉니다 (-1= ) ) .

정규 표현식 자체는 일치 0\?.:하고 제거하거나 (다음 항목 만 남김 :) 또는 1\?.:.뒤에있는 값으로 대체합니다 ?.


정규식이 오른쪽에서 시작되면 1st 대신 st 일치 를 처리하면 안 -1됩니까?
Leaky Nun

@LeakyNun 불행히도, 나는 한도를 적용하기 전에 일치를 뒤집는 것 같아요.
Martin Ender

10

하스켈, 106 (101) 100 90 83 바이트

이것은 패턴 Haskell의 패턴 매칭 기능에 크게 의존합니다. 우선, 우리는 b:a?x(일반적으로로 읽히는 x?a:b) 첫 번째 발생을 위해 그루터기 할 수 있도록 문자열을 뒤집고 값으로 대체합니다. 이것은 자동으로 올바른 연관성을 제공합니다 . 여기서 우리는 x:xs패턴 을 사용 합니다. 이것이 기능 f이 수행하는 것입니다. 그런 다음 기본적으로 적용합니다f 단일 숫자 (0 또는 1)가 남을 때까지 반복해서 출력에 합니다.

12 바이트 동안 @Lynn에게 감사합니다!

f(b:':':a:'?':x:l)|x>'0'=a:l|1>0=b:l
f(x:l)=x:f l
f x=x
until((<2).length)f.reverse

8

Brainfuck, 82 64 63 바이트

+
[
  ,>>,>
  +++++++[<---<<-[------>>]<-]
  <<
  [
    ->[<++>[+]]
  ]
  +>[>>]
  <<<-
]
<.

출력은 \xff위해 0\x00대한1 . brainfuck 구현은 시작 셀의 왼쪽으로 이동할 수 있어야합니다.

이것은 본질적으로 xsot의 Python answer 와 동일한 접근 방식을 사용 하지만 초기 82 바이트 제출과 비교할 때 분기가 따르기가 더 어려울 수 있습니다.

-
[
  +
  [
    ->,,>+++++++[<--------->-]
    <[<++>[+]]
    <
  ]
  ,->,>+++++++[<[-------<]>>-->-]
  <[<]
  <
]
>>.

(이 솔루션의 경우 출력이 \xfefor 0\xfffor 1이며 입력이 줄 바꿈으로 끝나면 더 넓은 호환성이 달성됩니다.)

xsot의 솔루션을 분석하기 위해 귀찮게 할 수 없다면 아이디어는 다음과 같습니다. 왼쪽에서 오른쪽으로 진행하십시오. 보이면 1?탐욕스럽게 버리십시오. 네가 본다면0? 해당 항목과 해당 항목 사이의 모든 을 삭제: . 때 ?두 번째 문자, 정지 루프로 표시하고, 나머지 문자열의 첫 번째 문자를 인쇄하지 않습니다.

따라서 82 바이트 솔루션은 실제로 해당 체계를 매우 밀접하게 반영합니다. 내부 루프 핸들0? xsot의 내부 루프와 마찬가지로을 합니다. 입력 문자를 확인하지 않고 메인 루프에 들어가려면 약간의주의가 필요합니다. 즉, 우리는 두 번째 문자가 ?메인 루프의 끝에서 한 번 인지, 메인 루프에 들어가기 전에 시작 부분 이 아닌지 확인하고 싶습니다 .

63 바이트 솔루션은 본질적으로 내부 및 외부 루프를 하나로 결합합니다. 루프 사이의 유사성을 고려했을 때 가능하다고 생각했습니다. 메인 루프의 메모리 레이아웃은 다음과 같이 설명 할 수 있습니다.

[s] d c

여기서 [x]현재 셀을 의미합니다- s시작은 우리가 여전히 루핑하고 있음을 나타내는 더미가 아닌 0이 아닌 값으로 시작하며 입력 문자 ( 0또는 1)로 즉시 덮어 씁니다 . d셀 우리는 중간에있는 경우에, (네거티브)의 깊이를 가지고 0?, 그렇지 0. 이 c중 하나가 될 것입니다 ?또는 :개행 문자 또는 EOF 나.

업데이트 후 sc, 우리는 처리 0?업데이트하여 케이스를 d, 그렇지 않으면 우리의 현재 값을 사용하여, 그에 따라 포인터 조정 c의 값으로 d우리가 수행하는 경우 다음 반복에서, 또는 정지.


7

파이썬 2, 76 74 73 72 바이트

a=`id`
for c in input()[::-1]:a=(c+a,a[ord(c)*7%9]+a[4:])[a>'?']
print a

문자열 리터럴로 입력하면 피할 수 있습니다. raw_ 있습니다.

출력은 0또는 1뒤에옵니다 <built-in function id>.


1
하하, 방금 b lang에 대한 귀하의 답변을 읽었으며 거의 ​​동일한 답변을 게시하려고했습니다! 추가 최적화가 있습니다 :3>>int(c)
xsot

이것이 어떻게 작동하는지 설명해 주시겠습니까? 정말 깔끔하게 보입니다
WorldSEnder

@WorldSEnder 생각하기 까다로울 수 있지만 일단 이해하면 이해하기 쉬운 솔루션 유형이라고 생각합니다. 다른 솔버도 마찬가지로 문자열을 거꾸로 실행하고 가장 오른쪽 조건을 반복적으로 처리합니다.
Mitch Schwartz

`id`트릭…! 잘 했어요 :)
Lynn

5

파이썬 2, 89 바이트

s=input()
while'?'<=s[1:]:
 n=s<'1'
 while n:s=s[2:];n+=-(s[1]<'?')|1
 s=s[2:]
print s[0]

입력은 문자열 리터럴로 사용됩니다.


5

Grime , 34 31 바이트

E=d|d\?E.E
e`\1|\1\?_.E|\0\?E._

인쇄 1truthy 입력 및 0falsy 사람을위한. 온라인으로 사용해보십시오! 마지막 테스트 사례는 불행히도 TIO의 메모리가 부족합니다.

설명

오른쪽 연관성은 본질적으로 in a?b:c에서 a항상 0또는 1더 이상 표현되지 않음을 의미합니다. 나는 그런 식과 같은 식과 일치하는 패턴을 재귀 적으로 정의하고 그에 대한 입력을 검사합니다. 또한 s가 모두 확인 되면 모든 :것이 실제로인지 확인 할 필요가 없습니다 . 입력 에 s와 s 가 같고 일부 가 잘못 분류 된 경우 해당 항목 이 일치하지 않으며 Grime의 일치 엔진이 역 추적합니다.:??:?::

E=d|d\?E.E
E=                      Define nonterminal E (for "expression") as
  d|                     a digit, OR
    d                    a digit,
     \?                  a literal ?,
       E                 a match of E,
        .                any character (will match a :), and
         E               another match of E.
e`\1|\1\?_.E|\0\?E._
e`                      Match entire input against this pattern (truthy expression):
  \1|                    a literal 1, OR
     \1\?                a literal 1?,
         _               a recursive match of truthy expression,
          .              any character (will match a :), and
           E|            any expression, OR
             \0\?E._     the same, but with 0 in front, and _ and E swapped.

5

하스켈, 79 71 70 62 60 56 바이트

편집 : 3 바이트의 경우 @Zgarb와 4 바이트의 경우 @nimi에게 감사합니다!

e(x:'?':r)|a:_:s<-e r=last$e s:[a:tail(e s)|x>'0']
e x=x

이것은 "일부 고정 값"-출력 규칙을 다소 남용 하는 재귀 적 접근 입니다 . 편집 : 튜플을 제거하면 8 바이트가 절약 될뿐만 아니라 더 좋은 출력이 생성됩니다."0" 또는 "1".

언 골프 버전 :

eval (x:'?':r1) = if x=='1' then (a, r3) else (b, r3)
    where (a,':':r2) = eval r1
          (b, r3)    = eval r2
eval (x:r) = (x,r)

어떻게 작동합니까?
eval함수는 암시 적 표현식 트리를 통과합니다.

eval 1?0?0:1:0?1:0 -> eval 1?          :
                             eval 0?0:1 eval 0?1:0

그리고 형식의 튜플을 반환합니다 (result, rest).
첫 번째 패턴은 (x:'?':r1)일치 x'1'r1"0?0:1:0?1:0". 하위 표현식 eval을 재귀 적으로 적용 r1하여 하위 표현식 을 평가 0?0:1하고를 반환합니다 (0,":0?1:0"). 이것을 패턴 과 일치 (a,':':r2)시키면 a=0r2=0?1:0. 이 하위 화학식은 순환되도록 평가 b='0'하고 r3="". 있는지 확인 x이다 '1'또는 '0'대가 중 하나 (a, r3)또는 (b, r3).


1
좋은 접근 방식! 겠습니까 x>'0'대신에 일을 x=='1'?
Zgarb

고마워, 나는 문자를 다루는 동안 그것을 생각하지 않았다.
Laikoni

1
내가 생각하는 당신은 또한 대체 할 수 있습니다 ':'_.
Zgarb

예, 그런 다음 코드는 just 대신 임의의 구분 기호로 작동합니다 :. 다시 감사합니다!
Laikoni

1
좋은! 당신은 교체 할 수 있습니다 if .. then .. elselast$e s:[a:tail(e s)|x>'0'].
nimi

3

자바 스크립트 (ES6), 53 바이트

f=s=>s[1]?f(s.replace(/0\?.:|1\?(.):.(?!\?)/,"$1")):s

반환 0또는 1유효한 입력; 유효하지 않은 입력을 위해 정지합니다. 설명 : JavaScript에서 문자열을 뒤집는 것이 어색하기 때문에 첫 번째 71 바이트 시도는 부정적인 예측을 사용하여 연결성을 ?방해합니다.

f=s=>s[1]?f(s.replace(/(.)\?(.):(.)(?!\?)/,(_,a,b,c)=>+a?b:c)):s

이것은 다소 길기 때문에 의사 결정을 정규 표현식에 통합하여 문제를 개선 할 수 있을지 궁금했습니다. 결과적으로 71 바이트가 걸리기 때문에 즉각적인 성공은 아니 었습니다.

f=s=>s[1]?f(s.replace(/0\?.:(.)(?!\?)|1\?(.):.(?!\?)/,"$1$2")):s

그 다음 날 그에게 발생 0?0:0?1:연관성에 대한 걱정없이, 항상 어떤 작전을하지 않습니다. 이것은 거의 25 %를 절약했습니다.


상단에 코드 블록이 없습니다 f=. 바이트 수를 고려하고 있는지 확인하지 않았습니다.
Patrick Roberts

@PatrickRoberts 나는 로그에서 복사하기 때문에 영원히 그것을하고 있습니다. 왜냐하면 할당 결과 만 보여줍니다 (물론 비 재귀 함수에 충분합니다).
Neil

@Neil 출력 대신 로그 입력에서 복사 할 수 있음
ASCII 전용

@MarsUltor 로그 입력에는 프롬프트를 포함하므로 제외해야합니다. 이것은 비 재귀 함수에 대한 어색한 추가 단계이므로 기본적으로 출력에서 ​​복사합니다.
Neil

3

Perl, 32 + 1 ( -p플래그) = 33 바이트

그의 솔루션이 내 것보다 14 바이트 짧았 기 때문에 @Mitch Swartch의 완전한 신용 !
또한 Mitch보다 1 바이트 더 긴 솔루션을 제안한 @Neil 에게 감사드립니다 .

s/.*\K(0\?..|1\?(.)..)/\2/&&redo

또는 실행 -p뿐만 아니라 플래그가 필요 합니다. 예를 들면 :-M5.010-E

perl -pE 's/.*\K(0\?..|1\?(.)..)/\2/&&redo' <<< "0
0?0:1
0?1?0:1:1
1?0:1?0?1:1?1:0:1?1?1:1:1?0:1
0?0?1?0?0:1:0?0:0:0?0?1:1:1?0:1:0?0?0?1:0:0?1:1:1?1?0:1:1"

설명 : 그것은 기본적으로의 블록을 감소 a?b:c(끝에서 시작 확실히 더 할 수 없습니다 ?로 다음) b또는 c의 truthness에 따라 a문자열 만 포함 할 때까지 반복, 1또는 0.


는 않습니다 -점수에 포함되지? 흠 흥미로운 ... 좋은 답변입니다!
MayorMonty

1 라이너는 @MayorMonty 사용하여 명령 라인을 호출 할 수있다 perl -e '<code>'따라서는 추가 p단지 1 바이트를 요한다 perl -pe '<code>'.
Neil

@Neil Ahh, 그 말이
맞습니다

실제로 문자열을 되돌릴 필요가 없습니다.에 대한 부정적인 미리보기를 할 수 있습니다 ?.이 방법으로 이것을 34 바이트로 줄일 수있었습니다.
Neil

여기에 32 + 1 :s/.*\K(1\?(.)..|0\?..)/\2/&&redo
미치 슈워츠

2

파이썬 3, 93 69 바이트

def f(s):z=s.pop;r=z(0);return s and':'<z(0)and(f(s),f(s))[r<'1']or r

입력은 문자열을 문자 목록으로, 출력은 "0"또는"1"

>>>f(list("0?0:1"))
<<<"1"

언 골프 버전 :

def parse(s):
    predicate = s.pop(0)
    if s and s.pop(0) == '?':
        left, right = parse(s), parse(s)
        if predicate == '0':
            return right
        return left
    return predicate

또 다른 시도이지만 상당히 많은 바이트가 있습니다.

i=input()[::-1]
a=[i[0]]
for o,z in zip(i[1::2],i[2::2]):a+=[z]if o<'?' else[[a.pop(),a.pop()][z>'0']]
print(a[0])

답은 함수일 수 있습니다. 두 번째 줄을 제거 할 수 있습니다.
Lynn

테스트 사례를 통과하지 못하므로 명확하게 테스트되지 않았으며 ungolfed 버전은 런타임 오류를 발생시킵니다. 그래도 기본 아이디어는 좋습니다. 일부 조정을 통해 파이썬 3에서 파이썬이 69에서 68를 얻을
미치 슈워츠

1
글쎄, 대답을 내 자신으로 편집하는 것보다 답을주는 것이 더 합리적이라고 생각합니다 (나는 대답을보기 전에이 종류의 접근 방식에 대해 생각하지 않았기 때문에). 여기에 내가 언급 한 68이 있으며 def f(s):x=s.pop(0);return[]<s<s.pop(0)>'>'and(f(s),f(s))[x<'1']or x, 편집 거리가 작은 Python 3의 경우 def f(s):z=s.pop;r=z(0);return s and':'<z(0)and(f(s),f(s))[r<'1']or r.
Mitch Schwartz

고마워 @MitchSchwartz, 왼쪽에서 대신 거의 오른쪽에서 구문 분석
gotcha

1
다른 방법으로, 오른쪽 대신에 왼쪽 ~~~
WorldSEnder

1

SED, 75 74 68 (-r의 경우 40 + 1) 41

:
s,(.*)1\?(.):.,\1\2,
s,(.*)0\?.:,\1,
t

당신은 아마 자신의 MitchSchwartz의 트릭 @ 사용하여이 줄일 수 있습니다 주석을 사용 할 수 있지만, (.*)그리고 여분의 교체 기간을 추가 할 수 있습니다.
Neil

@ Neil, 당신은 옳을 수 있지만 어떻게 작동시키는 지 알 수 없습니다.
Riley

코멘트 형식이 혼란 스러울 수 있으므로 채팅으로 작성했습니다. chat.stackexchange.com/transcript/message/31709640#31709640
Mitch Schwartz

@MitchSchwartz Heh, 빈 레이블이 작동합니까? 그러나 나는 당신이 \3대신 을 의미한다고 생각합니다 \2. 또한 라인을 결합하여 ;얻을 수 :;s/(.*)(1\?(.):.|0\?.:)/\1\3/;t있습니다.
Neil

@Neil은 \3실수로 이전 버전을 복사했음을 의미합니다. 세미콜론에 대해 알고 있습니다. 그러나 ck, 왜 세미콜론을 사용하고 싶습니까?
Mitch Schwartz

0

배쉬 + GNU 유틸리티, 42

rev|sed -r ':
s/(.):.\?0|.:(.)\?1/\1\2/
t'

대부분의 다른 패턴 일치 답변과 유사한 아이디어입니다.

Ideone .


0경우 첫 번째 문자를 캡처 할 필요가 없으므로 5 바이트가 절약됩니다.
Neil
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.