Tạo một trình phân tích cú pháp Boolean (tiếp theo)


8

Tiếp tục thử thách này vì tác giả đã biến mất và câu hỏi được đóng lại.


Những gì bạn cần làm là tạo một trình phân tích cú pháp Boolean.


Biểu thức Boolean, trong trường hợp bạn chưa nghe về chúng, có hai đầu vào và một đầu ra.

Có bốn "cổng" trong số học boolean, cụ thể là:

  • HOẶC (đại diện bởi |) (toán tử nhị phân, giữa các đối số)
  • AND (đại diện bởi &) (toán tử nhị phân, giữa các đối số)
  • XOR (đại diện bởi ^) (toán tử nhị phân, giữa các đối số)
  • KHÔNG (đại diện bởi !) (toán tử đơn nguyên, đối số bên phải)

Các cổng này hoạt động trên đầu vào của chúng là true (đại diện bởi 1) hoặc false (đại diện bởi 0). Chúng ta có thể liệt kê các đầu vào có thể ( ABtrong trường hợp này) và đầu ra ( O) bằng bảng chân lý như sau:

XOR
A|B|O
-----
0|0|0
0|1|1
1|0|1
1|1|0

OR
A|B|O
-----
0|0|0
0|1|1
1|0|1
1|1|1

AND
A|B|O
-----
0|0|0
0|1|0
1|0|0
1|1|1

NOT
A|O
---
0|1
1|0

Một ví dụ đầu vào sẽ là 1^((1|0&0)^!(1&!0&1)), sẽ đánh giá:

 1^((1|0&0)^!(1&!0&1))
=1^(( 1 &0)^!(1&!0&1))
=1^(   0   ^!(1&!0&1))
=1^(   0   ^!(1& 1&1))
=1^(   0   ^!(  1 &1))
=1^(   0   ^!    1   )
=1^(   0   ^    0    )
=1^0
=1

Đầu ra sẽ là 1.

Chi tiết

  • Như đã thấy trong ví dụ, không có thứ tự phổ biến. Tất cả được đánh giá từ trái sang phải, ngoại trừ khi bên trong dấu ngoặc đơn, cần được đánh giá trước.
  • Đầu vào sẽ chỉ chứa ()!^&|01.
  • Bạn có thể chọn bất kỳ ký tự 8 byte nào để thay thế 8 ký tự ở trên, nhưng chúng phải có ánh xạ 1 đến 1 và phải được nêu rõ.
  • Cụ thể, hàm evalkhông được phép sử dụng trên bất kỳ chuỗi nào có nguồn gốc từ đầu vào . Cụ thể, chức năng input(hoặc tương đương trong ngôn ngữ) và bất kỳ chức năng nào gọi nó không thể được sử dụng bởi eval. Bạn cũng không thể nối inputchuỗi vào bên trong eval.

Chấm điểm

Đây là . Giải pháp ngắn nhất trong byte thắng.


Cheddar đã tích hợp sẵn để tạo ngăn xếp cuộc gọi từ một chuỗi có bị quá không?
Hạ cấp

2
Bạn có thể thêm một số trường hợp thử nghiệm?
Conor O'Brien

@ CᴏɴᴏʀO'Bʀɪᴇɴ Trường hợp thử nghiệm nào bạn muốn xem?
Nữ tu bị rò rỉ

@KennyLau Một vài cái phức tạp, idk
Conor O'Brien

Có bất kỳ điều kiện mà các trường hợp thử nghiệm đã không xử lý? Tôi nghĩ rằng nó đã xử lý khá nhiều thứ rồi.
Nữ tu bị rò rỉ

Câu trả lời:


6

JavaScript (ES6) 116 byte

chỉnh sửa thx @ user81655 cho 3 byte được lưu và tìm thấy lỗi

s=>[...s].map(x=>x<2?v=m[x]:x<6?m=[,,m[1]+m[0],0+v,v+1,v+(1^v)][x]:x>6?v=o.pop()[v]:m=o.push(m)&&a,o=[v=a=m='01'])|v

Có lẽ không phải là cách tiếp cận tốt nhất, nhưng không có toán tử eval và không boolean, chỉ là các bảng chân lý.

Nhân vật được sử dụng:

  • ! -> 2
  • & -> 3
  • | -> 4
  • ^ -> 5
  • (-> 6
  • ) -> 7

Kiểm tra

f=s=>[...s].map(x=>x<2?v=m[x]:x<6?m=[,,m[1]+m[0],0+v,v+1,v+(1^v)][x]:x>6?v=o.pop()[v]:m=o.push(m)&&a,o=[v=a=m='01'])|v

console.log=(...x)=>O.textContent+=x+'\n'

test=[ ["1^((1|0&0)^!(1&!0&1))",1] 
// be more careful, step by step
,["0&0",0],["0&1",0],["1&0",0],["1&1",1]
,["0|0",0],["0|1",1],["1|0",1],["1|1",1]
,["0^0",0],["0^1",1],["1^0",1],["1^1",0]
,["0&!0",0],["0&!1",0],["1&!0",1],["1&!1",0]
,["0|!0",1],["0|!1",0],["1|!0",1],["1|!1",1]
,["0^!0",1],["0^!1",0],["1^!0",0],["1^!1",1]
,["!0&0",0],["!0&1",1],["!1&0",0],["!1&1",0]
,["!0|0",1],["!0|1",1],["!1|0",0],["!1|1",1]
,["!0^0",1],["!0^1",0],["!1^0",0],["!1^1",1]
// nand, nor
,["!(0&0)",1],["!(0&1)",1],["!(1&0)",1],["!(1&1)",0]
,["!(0|0)",1],["!(0|1)",0],["!(1|0)",0],["!(1|1)",0]
     ]

test.forEach(([x,check]) => {
  // remap operators (each one on its line, just to be clear)
  var t = x.replace(/!/g,"2")
  t = t.replace(/&/g,"3")
  t = t.replace(/\|/g,"4")
  t = t.replace(/\^/g,"5")
  t = t.replace(/\(/g,"6")
  t = t.replace(/\)/g,"7")
  r = f(t)
  console.log((r==check?'OK':'KO')+' '+x +' '+r)
})
<pre id=O></pre>


1
Bạn có thực sự có ý nghĩa x>7?
Neil

r=f(x.replace(/./g,c=>"01!&|^()".indexOf(c)))
Neil

@Neil tôi sẽ kiểm tra, cảm ơn. Tất nhiên nếu> 6
edc65

@Neil Tôi đang thêm trường hợp thử nghiệm. Tôi khá chắc chắn rằng với sự kết hợp và giao hoán của các nhà khai thác, KHÔNG nên luôn luôn hoạt động
edc65

Tôi đã mất một thời gian để tìm hiểu lý do tại sao (nói) 0|!0hoạt động, nhưng bây giờ tôi làm, có upvote của tôi.
Neil

5

Võng mạc, 49 byte

+`(<1>|!0|1[ox]0|0[ox]1|1[ao]1)|<0>|!1|\d\w\d
$#1

Tôi không biết làm thế nào mà nó đi ra quá ngắn.

Ánh xạ nhân vật:

^ -> x
& -> a
| -> o
( -> <
) -> >

1, 0!được giữ nguyên.

Này hoạt động bằng cách thay thế tất cả các biểu thức truthy (đơn 1trong ngoặc đơn !0, 1&1, 1^0, 0|1, vv) với 1, và tất cả khác (đơn 0trong ngoặc đơn !1, 1&0, 1^1, 0|0, vv) với 0.

Hãy thử trực tuyến!
Hãy thử trực tuyến với bản đồ nhân vật tự động!


3

grep + shell utils, 131 byte

rev|grep -cP '^(((0|R((?9)(x(?1)|a(?4))|(?2)([oxa](?4)|a(?1)|))L|(1|R(?1)L)!)(!!)*)[xo](?1)|(1|R(?1)L|(?2)!)([ao](?1)|[xo](?4)|))$'

Các ký tự sau được đổi tên:

( -> L
) -> R
| -> o
& -> a
^ -> x

Tôi bắt đầu thử viết một giải pháp grep, nhưng phát hiện ra rằng nó không hoạt động tốt với các toán tử infix liên kết trái. Tôi cần phải có một mô hình như (chuỗi toán tử) = (chuỗi toán tử) (nhị phân op) (toán hạng đơn), nhưng điều này chứa một đệ quy vô hạn có thể, vì vậy grep từ chối thực hiện nó. Nhưng tôi nhận thấy rằng tôi có thể phân tích các toán tử liên kết phải. Điều này làm cho người !vận hành đau đớn, nhưng nó vẫn có thể. Vì vậy, tôi đã tạo một biểu thức chính để tính toán các biểu thức boolean ngược và gửi đầu vào qua rev. Bản thân regex, khớp với các biểu thức thực, là 116 byte.

TODO: chọn các ký tự khác nhau cho đầu vào để tôi có thể phân biệt tất cả các nhóm toán tử được sử dụng với các lớp ký tự tích hợp.


(?9)nghĩa là gì?
Nữ tu bị rò rỉ

Nó có nghĩa là lấy nhóm bắt giữ thứ 9 và thực hiện lại nó (như khác biệt với \9nghĩa là phù hợp với những gì nhóm bắt giữ thứ 9 khớp). Vì vậy, ví dụ (\d)\1khớp với cùng một chữ số hai lần, trong khi (\d)(\?1)khớp với hai chữ số bất kỳ.
Neil

2

Python, 210 byte

from operator import*;
def t(o):c=o.pop(0);return ord(c)-48if c in"01"else[p(o),o.pop(0)][0]if"("==c else 1-t(o)
def p(o):
 v=t(o)
 while o and")"!=o[0]:v=[xor,or_,and_]["^|&".index(o.pop(0))](v,t(o))
 return v

Hậu duệ thực sự xấu, tôi hy vọng điều này sẽ được đánh bại trong một nhịp tim.


2

Toán học, 139 129 byte

a=StringPartition;StringReplace[#,{"(0)0&00&11&00|00^01^1"~a~3|"!1"->"0","(1)1&10|11|01|10^11^0"~a~3|"!0"->"1"},1]&~FixedPoint~#&

Một giải pháp thay thế chuỗi đơn giản đạt điểm số tốt hơn nhiều so với tôi mong đợi.


2

JavaScript ES6, 223 byte

x=>(Q=[],S=[],[...x].map(t=>{q=+t&&Q.push(t);if(t==")")while((a=S.pop())!="(")Q.push(a);else if(!q)S.push(t)}),k=[],p=_=>k.pop(),Q.concat(S.reverse()).map(e=>k.push(+e||e<"#"?1-p():e<"'"?p()&p():e<","?p()|p():p()^p())),p())

Sử dụng một thuật toán sân shunting.

x=>(Q=[],S=[],[...x].map(t=>{q=+t&&Q.push(t);if(t==")")while((a=S.pop())!="(")Q.push(a);else 
if(!q)S.push(t)}),k=[],p=_=>k.pop(),Q.concat(S.reverse()).map(e=>k.push(+e||e<"#"?1-p():e<"'"
?p()&p():e<","?p()|p():p()^p())),p())

Sử dụng +cho OR, !cho phủ định, ^cho XOR và &cho và. 01được sử dụng cho các giá trị tương ứng của họ. Chắc chắn, tôi có thể đánh gôn một số bằng cách tạo số cho các nhà khai thác, nhưng tôi không giành được giải thưởng JavaScript ngay cả khi tôi làm vậy, vì vậy tôi nghĩ rằng tôi sẽ làm cho nó ít nhất có thể đọc được và chính xác.


1

C, 247

Chơi gôn

b(char*s){int i,j,k,l;if(*s==40){for(j=i=1;i+=s[++j]==41?-1:s[j]==40?1:0,i;);s[j++]=0;b(s+1);sprintf(s,"%s%s",s+1,s+j);}!s[1]?:(b(s+1),i=*s,j=1,k=s[1],i>47&i<50?:(s[1]=i==33?(j=0,k^1):(l=s[-1],i==38?k&l:i==94?k^l|'0':k|l),sprintf(s-j,"%s",s+1)));}

Ungolfed, với main()(lấy biểu thức là 1st arg). Phiên bản chơi gôn không có bản in gỡ lỗi và sử dụng mã ascii 2 chữ số thay vì chữ char ( 40 == '('). Tôi có thể đã lưu một số ký tự bằng cách ánh xạ ()|^&!tới 234567- điều này sẽ làm cho nhiều thao tác và kiểm tra dễ dàng hơn sau khi trừ đi 48từng ký tự.

char*z;                 // tracks recursion depth; not used in golfed version
b(char*s){
    int i,j,k,l;
    printf("%u> '%s'\n", s-z, s);
    if(*s=='('){        // handles parenthesis
        for(j=i=1;i+=s[++j]==')'?-1:s[j]=='('?1:0,i;);
        s[j++]=0;
        b(s+1);         // s+1 to s+j gets substituted for its evaluation
        sprintf(s,"%s%s",s+1,s+j);
    }
    !s[1]?:(            // if 1 char left, return
        b(s+1),         // evaluate rest of expression
        i=*s,
        j=1,
        k=s[1],
        printf("%u: '%c'\n", s-z, i),
        i>47&i<50?:(    // if 0 or 1, skip substitution
                        // otherwise, perform boolean operation
            s[1]=i=='!'?(j=0,k^1):(l=s[-1],i=='&'?k&l:i=='|'?k|l:k^l|'0'),
                        // and replace operation with result
            sprintf(s-j,"%s",s+1),printf("%u= '%s'\n", s-z, s-j)));
    printf("%u< '%s'\n", s-z, s);
}
int main(int argc, char **argv){
    char *s;    
    sscanf(argv[1],"%ms",&s);
    z=s;
    b(s);
    printf("%s => %s\n", argv[1], s);
}

+1 cho for(j=i=1;i+=s[++j]==')'?-1:s[j]=='('?1:0,i;);.
Leaky Nun

1

Java, 459 byte

String p(String s){int x,y;while((y=s.indexOf("b"))>=0){x=s.lastIndexOf("a",y);s=s.replaceAll(s.subString(x,y+1),p(s.subString(x+1,y)));}String t,a="1",b="0";while(s.indexOf("!")>=0){s=s.replaceAll("!0",a);s=s.replaceAll("!1",b);}while(s.length()>1){t=s.subString(0,3);if(t.charAt(1)=='l')s=s.replaceFirst(t,t.equals("0l0")?b:a);else if(t.charAt(1)=='&')s=s.replaceFirst(t,t.equals("1&1")?a:b);else s=s.replaceFirst(t,t.charAt(0)==t.charAt(2)?b:a);}return s;}

AND&

ORl(chữ thường L)

XORx(hoặc bất kỳ nhân vật nào khác chơi hay với Stringcác phương thức như String.replaceAll(...))

NOT!

(a

)b

đây là phiên bản dễ đọc hơn:

String parseBoolean( String str ) {
    int start,end;
    //look for matching brackets ab
    while( (end = str.indexOf( "b" )) >= 0 ) {
        start = str.lastIndexOf( "a", end );
        str = str.replaceAll( str.subString( start, end + 1 ), parseBoolean( str.subString( start + 1, end ) ) );
    }
    String temp, one = "1", zero = "0";
    //handle all the !'s
    while( str.indexOf( "!" ) >= 0 ) {
        str = str.replaceAll( "!0", one );
        str = str.replaceAll( "!1", zero );
    }
    //handle the remaining operators from left to right
    while( str.length() > 1 ){
        temp = str.subString( 0, 3 );
        //check for OR
        if( temp.charAt( 1 ) == 'l' )
            str = str.replaceFirst( temp, temp.equals( "0l0" ) ? zero : one );
        //check for AND
        else if(t.charAt(1)=='&')
            str = str.replaceFirst( temp, temp.equals( "1&1" ) ? one : zero );
        //handle XOR
        else 
            str = str.replaceFirst( temp, temp.charAt( 0 ) == temp.charAt( 2 ) ? zero : one );
    }
    return str;
}

thử trực tuyến


1
Như mọi khi với môn đánh gôn Java, điều tôi thích nhất là thay thế các ký tự char bằng các số nguyên của chúng bất cứ nơi nào tôi có thể. Trong trường hợp này, đó sẽ là trong cả hai chỉ số thông thường và so sánh charAt. Ngoài ra, nếu bạn thay đổi ký tự cho AND thành "n" thay vì "&", bạn có thể sử dụng các câu lệnh <hoặc> với các if đơn khi kiểm tra thao tác nào bạn cần thực hiện.
Màu xanh

1
Ồ, một điều nữa. Bạn có thể nhân đôi cuộc gọi để thay thế All trong vòng lặp while, đồng thời tiết kiệm cho bạn các dấu ngoặc đó.
Màu xanh

@Blue tôi luôn quên char charals để ints, cảm ơn. Tôi không chắc ý của bạn là gì khi nhân đôi cuộc gọi thay thế. Tất cả cuộc gọi cho!
Jack Ammo

s = s.replace ALL ("! 0", a) .replaceAll ("! 1", b);
Màu xanh

1

Java, 218

Sử dụng khớp mẫu, nhưng tránh các thay thế không theo thứ tự của lần thử Java thất bại trước đây của tôi (đôi mắt sắc nét ở đó, @Kenny Lau !).

Chơi gôn

String e(String s){Matcher m=Pattern.compile("(<1>|1o[01]|0o1|1a1|1x0|0x1|n0)|(<0>|0o0|0a[01]|1a0|1x1|0x0|n1)").matcher(s);return m.find()?e(s.substring(0,m.start())+(m.group(1)==null?"0":"1")+s.substring(m.end())):s;}

Ungolfed, đọc đầu vào từ các đối số và áp dụng ánh xạ oaxncho |&^!<>cho ():

import java.util.regex.*;

public class B{
    String e(String s){
        System.out.println(s);
        Matcher m=Pattern
            .compile(
                "(<1>|1o[01]|0o1|1a1|1x0|0x1|n0)|"+
                "(<0>|0o0|0a[01]|1a0|1x1|0x0|n1)")
            .matcher(s);
        return m.find()?e(s.substring(0,m.start())+(m.group(1)==null?"0":"1")+s.substring(m.end())):s;
    }

    public static String map(String s, String ... replacements) {
        for (String r: replacements) {
            s = s.replace(r.substring(0,1), r.substring(1));
        }
        return s;
    }

    public static void main(String ... args){
        for (String s: args) System.out.println(new B().e(
            map(s,"(<",")>","|o","&a","!n","^x")
        ));
    }
}

Java m.group(i)cho bạn biết nhóm nào phù hợp; nhóm thứ nhất là cho sự thay thế thực sự và nhóm thứ hai cho những người sai. Điều này được lặp lại theo thứ tự từ trái sang phải nghiêm ngặt cho đến khi không có sự thay thế nào được thực hiện.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.