Artikel ini membawakan anda pengetahuan yang berkaitan tentang java Ia terutamanya memperkenalkan secara terperinci cara melaksanakan penapis ungkapan hubungan kompleks berdasarkan Java. Kod sampel dalam artikel diterangkan secara terperinci. Mari kita lihat.
Pembelajaran yang disyorkan: "tutorial video java"
Baru-baru ini, terdapat keperluan baharu, perlu Ungkapan hubungan kompleks disediakan di latar belakang untuk menganalisis sama ada pengguna memenuhi syarat berdasarkan ID yang ditentukan pengguna Tetapan latar belakang adalah serupa dengan syarat carian ZenTao
. tetapi berbeza Hanya terdapat dua kumpulan dalam Zen Tao, dan setiap kumpulan mempunyai sehingga tiga syarat
Kumpulan dan hubungan di sini mungkin lebih rumit Terdapat kumpulan dalam kumpulan, dan setiap syarat adalah ya dan atau. perhubungan. Atas sebab kerahsiaan, prototaip tidak akan dikeluarkan.
Melihat keperluan ini, sebagai bahagian belakang, perkara pertama yang terlintas di fikiran ialah rangka kerja ekspresi seperti QLEpress Selagi anda membina ungkapan, anda boleh menapis pengguna sasaran dengan cepat dengan menghuraikan ungkapan tersebut Sayang sekali rakan sekelas front-end berhenti, kerana sebagai rangka kerja dipacu data menggunakan vue atau bertindak balas, terlalu sukar untuk menukar ungkapan ke dalam bentuk di atas, jadi saya memikirkannya dan memutuskan untuk menentukan struktur data sendiri . , laksanakan penghuraian ungkapan. Mudah untuk diproses oleh pelajar hadapan.
Walaupun ungkapan dilaksanakan menggunakan kelas, pada asasnya ungkapan itu masih merupakan ungkapan mudah: Biarkan syaratnya ialah a, b, c, d , kita membina ungkapan di. akan:
boolean result=a>100 && b=10 || (c != 3 && d ec5e28ddc4f54a5f23f82dd8b3024c02100 daripada 100).
Selain itu, terdapat beberapa atribut seperti Persatuan (dan, atau) dan Keutamaan pengiraan .
Jadi kita ringkaskan ungkapan:
Biar a>100 =>A,b=10 =>B,c!=3=>C ,d1f95226a8acdafab5dc28f716ab5c5e4 D, jadi kita dapat:
result=A && B || (C && D)
Sekarang timbul persoalan, bagaimana untuk menangani keutamaan?
Untuk ungkapan di atas, adalah jelas bahawa ini adalah ungkapan tertib standard yang dipelajari di kolej, jadi mari kita lukis rajah pokoknya:
Mengikut ini gambar, kita dapat melihat dengan jelas bahawa A dan B dan C dan D berada pada tahap yang sama Oleh itu, kita mereka bentuk konsep hierarki Deep mengikut teori ini dapatkan:
Kita dapat melihat bahawa sebagai nod daun (bahagian hijau dalam gambar di atas), berbanding dengan hubungan pengiraan pengiraannya, apabila ia menemuinya, ia mesti dikira dahulu. Jadi untuk keutamaan mendalam, kita hanya perlu mempertimbangkan nod bukan daun, iaitu bahagian nod biru dalam rajah di atas, jadi kita dapat, konsep pengiraan keutamaan boleh ditukar menjadi ungkapan Kedalaman.
Mari kita lihat semula gambar di atas Hubungan antara Deep1 ialah DAN atau hubungan antara hasil yang dikira oleh dua ungkapan A dan B dan C dan D dalam Deep2. C Dan D ialah G2, jadi kita dapati terdapat dua jenis perkaitan nod perhubungan, satu ialah KeadaanKeadaan, dan satu lagi ialah Kumpulan
Pada ketika ini, prototaip kelas ini pada dasarnya ditentukan. Kelas ini termasuk
Perhubungan (Perhubungan), Medan Penghakiman (Medan), Pengendali (Pengendali), Nilai Operasi (Nilai), Jenis(Jenis), Kedalaman(Deep)
Namun, terdapat masalah dalam analisis di atas, kami menukar ungkapan itu kepada pokok. Jadi kita boleh mendapatkan salah satu ungkapan sepintas lalu:result=(A && B)||(C && D)
Jelas sekali, ia tidak konsisten dengan ungkapan asal kami Ini kerana kami hanya boleh merekodkan susunan pengiraan ungkapan di atas, tetapi tidak dapat mewakili ungkapan ini dengan tepat Ini kerana dalam proses menghuraikan ungkapan Dalam , ada bukan sahaja kedalaman, tetapi juga hubungan masa, iaitu ungkapan berurutan dari kiri ke kanan Pada masa ini, kandungan dalam G1 sebenarnya harus mempunyai kedalaman 1 dan bukannya 2 dalam ungkapan asal nombor jujukan , ubah pokok asal menjadi graf terarah:
Mengikut graf ini, kami boleh memulihkan satu-satunya ungkapan: result= A && B ||(C && D)
.
Baiklah, kami telah menganalisisnya untuk masa yang lama Sekarang setelah kami selesai menerangkan prinsip, mari kembali kepada soalan asal: Bagaimana untuk melaksanakan bahagian depan dan belakang? Bayangkan melihat gambar di atas nampaknya masih mustahil untuk dikendalikan kerana strukturnya masih terlalu rumit. Untuk bahagian hadapan, data harus mudah dilalui, dan untuk bahagian belakang, data harus mudah diproses, jadi pada masa ini kita perlu menukar gambar di atas menjadi tatasusunan.
Kaedah pelaksanaanSeperti yang dinyatakan di atas, struktur tatasusunan diperlukan Mari kita menganalisis bahagian ini secara terperinci Kami mendapati bahawa sebagai satu. nod daun, sentiasa boleh dinilai dahulu, jadi kita boleh memampatkannya dan meletakkan hubungan dalam salah satu ungkapan untuk membentuk atau ^A -> &&B
, di sini saya mulakan dengan biasa A&& -> B$
(^) dan End($) mewakili konsep permulaan dan akhir Untuk konsisten dengan prototaip produk, kami menggunakan cara pertama, iaitu simbol hubungan untuk mewakili hubungan dengan elemen sebelumnya, jadi kami. analisanya sekali lagi:
@Data @AllArgsConstructor @NoArgsConstructor @Accessors(chain = true) public class ExpressDto { /** * 序号 */ private Integer seq; /** * 深度(运算优先级) */ private Integer deep; /** * 关系运算符 */ private String relation; /** * 类型 */ private String type; /** * 运算条件 */ private String field; /** * 逻辑运算符 */ private String operator; /** * 运算值 */ private String values; /** * 运算结果 */ private Boolean result; }Sekarang struktur data akhirnya selesai, yang kedua-duanya mudah untuk penyimpanan dan (agak) mudah untuk paparan bahagian hadapan Sekarang bina ungkapan yang sedikit kompleks
A &&(( B || C )|| (D && E)) && F
[ {"seq":1,"deep":1,relation:"BEGIN","type":"CONDITION","field"="A"...}, {"seq":2,"deep":1,relation:"AND","type":"GROUP","field":""...}, {"seq":3,"deep":2,relation:"BEGIN","type":"GROUP","field":""...}, {"seq":4,"deep":3,relation:"BEGIN","type":"CONDITION","field":"B"...}, {"seq":5,"deep":3,relation:"OR","type":"CONDITION","field":"C"...}, {"seq":6,"deep":2,relation:"OR","type":"GROUP","field":""...}, {"seq":7,"deep":3,relation:"BEGIN","type":"CONDITION","field":"D"...}, {"seq":8,"deep":3,relation:"AND","type":"CONDITION","field":"E"...}, {"seq":9,"deep":1,relation:"AND","type":"CONDITION","field":"F"...} ]Sekarang soalan terakhir tinggal: bagaimana untuk menapis data melalui json iniMemandangkan intipati objek tatasusunan masih merupakan ungkapan infix, intipatinya masih merupakan parsing daripada ungkapan infix. Mengenai prinsip parsing, saya tidak akan memperkenalkannya di sini Secara ringkasnya, ia dilalui melalui timbunan data dan timbunan simbol mengikut kurungan (dipanggil kumpulan dalam kes kami baca artikel berikut. Ulasan Jadi kami mentakrifkan tiga pembolehubah:
//关系 栈 Deque<String> relationStack=new LinkedList(); //结果栈 Deque<Boolean> resultStack=new LinkedList(); // 当前深度 Integer nowDeep=1;Dengan merentasi tatasusunan, tolak perhubungan dan hasilnya ke dalam tindanan untuk diutamakan, ambil dua daripada nilai tindanan hasil, keluarkan pengendali relasi daripada tindanan relasi, tolaknya ke dalam tindanan semula selepas pengiraan, dan tunggu pengiraan seterusnya
for (ExpressDto expressDto:list) { if(!StringUtils.equals(expressDto.getType(),"GROUP")){ //TODO 进行具体单个表达式计算并获取结果 resultStack.push(expressDto.getResult()); // 将关系放入栈中 relationStack.push(expressDto.getRelation()); if(deep==0 && resultStack.size()>1){ //由于已处理小于0的deep,当前deep理论上是>=0的,0表示同等级,需要立即运算 relationOperator(relationStack, resultStack); } }else{ // 将关系放入栈中 relationStack.push(expressDto.getRelation()); } } private void relationOperator(Deque<String> relationStack, Deque<Boolean> resultStack) { Boolean lastResult= resultStack.pop(); Boolean firstResult= resultStack.pop(); String relation=relationStack.pop(); if(StringUtils.equals(relation,"AND")){ resultStack.push(firstResult&& lastResult) ; return; } if(StringUtils.equals(relation,"OR")){ resultStack.push( firstResult|| lastResult); return; }else{ throw new RuntimeException("表达式解析异常:关系表达式错误"); } }Mari kita bincangkan sempadan penting untuk diperhatikan: 1 Pertama sekali, kita berada pada tahap yang sama Terdapat hanya dua jenis perhubungan persatuan, dan dan, atau, dan keutamaan pengiraan kedua-dua jenis ini adalah sama. Oleh itu, di bawah Deep yang sama, hanya melintasi dan mengira dari kiri ke kanan. 2 Apabila menemui jenis GROUP, ia bersamaan dengan menemui "(", kita dapati bahawa elemen di belakangnya ialah Deep 1 hingga Deep -1 dan berakhir dengan ")", dan elemen dalam kurungan perlu mengambil keutamaan Pengiraan, iaitu, keutamaan yang dijana oleh "()" dikawal bersama oleh Deep dan Type=GROUP3 Apabila Deep berkurangan, ini bermakna ")" ditemui, dan bilangan Kumpulan yang tamat adalah sama dengan Bilangan yang dikurangkan dengan Deep, untuk penghujung ")", setiap kali ")" ditemui, kurungan tahap perlu diperiksa untuk melihat sama ada unsur-unsur tahap yang sama mempunyai telah dikira.
/** * 处理层级遗留元素 * * @param relationStack * @param resultStack */ private void computeBeforeEndGroup(Deque<String> relationStack, Deque<Boolean> resultStack) { boolean isBeginSymbol=StringUtils.equals(relationStack.peek(),"BEGIN");//防止group中仅有一个判断条件 while(!isBeginSymbol){//上一个运算符非BEGIN,说明该group中还有运算需要优先处理,正常这里应该仅循环一次 relationOperator(relationStack, resultStack); isBeginSymbol=StringUtils.equals(relationStack.peek(),"BEGIN"); } if(isBeginSymbol){ relationStack.pop();//该优先级处理完毕,将BEGIN运算符弹出 } }4. Apabila traversal tamat dan didapati elemen terakhir Deep tidak sama dengan 1, bermakna ada penghujung kurungan juga perlu untuk diproses Akhir sekali, kod lengkap:
/** * 表达式解析器 * 表达式规则: * 关系relation属性有:BEGIN、AND、OR 三种 * 表达式类型 Type 属性有:GROUP、CONDITION 两种 * 深度 deep 属性 根节点为 1,每增加一个括号(GROUP)deep+1,括号结束deep-1 * 序号req:初始值为1,往后依次递增,用于防止表达式解析顺序错误 * exp1:表达式:A &&(( B || C )|| (D && E)) && F * 分解对象: * [ * {"seq":1,"deep":1,relation:"BEGIN","type":"CONDITION","field"="A"...}, * {"seq":2,"deep":1,relation:"AND","type":"GROUP","field":""...}, * {"seq":3,"deep":2,relation:"BEGIN","type":"GROUP","field":""...}, * {"seq":4,"deep":3,relation:"BEGIN","type":"CONDITION","field":"B"...}, * {"seq":5,"deep":3,relation:"OR","type":"CONDITION","field":"C"...}, * {"seq":6,"deep":2,relation:"OR","type":"GROUP","field":""...}, * {"seq":7,"deep":3,relation:"BEGIN","type":"CONDITION","field":"D"...}, * {"seq":8,"deep":3,relation:"AND","type":"CONDITION","field":"E"...}, * {"seq":9,"deep":1,relation:"AND","type":"CONDITION","field":"F"...} * ] * * exp2:(A || B && C)||(D && E && F) * [ * {"seq":1,"deep":1,relation:"BEGIN","type":"GROUP","field":""...}, * {"seq":2,"deep":2,relation:"BEGIN","type":"CONDITION","field":"A"...}, * {"seq":3,"deep":2,relation:"OR","type":"CONDITION","field":"B"...}, * {"seq":4,"deep":2,relation:"AND","type":"CONDITION","field":"C"...}, * {"seq":5,"deep":1,relation:"OR","type":"GROUP","field":""...}, * {"seq":6,"deep":2,relation:"BEGIN","type":"CONDITION","field":"D"...}, * {"seq":7,"deep":2,relation:"AND","type":"CONDITION","field":"E"...}, * {"seq":8,"deep":2,relation:"AND","type":"CONDITION","field":"F"...} * ] * * * @param list * @return */ public boolean expressProcessor(ListTulis beberapa kes ujian mudah:list){ //关系 栈 Deque relationStack=new LinkedList(); //结果栈 Deque resultStack=new LinkedList(); // 当前深度 Integer nowDeep=1; Integer seq=0; for (ExpressDto expressDto:list) { // 顺序检测,防止顺序错误 int checkReq=expressDto.getSeq()-seq; if(checkReq!=1){ throw new RuntimeException("表达式异常:解析顺序异常"); } seq=expressDto.getSeq(); //计算深度(计算优先级),判断当前逻辑是否需要处理括号 int deep=expressDto.getDeep()-nowDeep; // 赋予当前深度 nowDeep=expressDto.getDeep(); //deep 减小,说明有括号结束,需要处理括号到对应的层级,deep减少数量等于组(")")结束的数量 while(deep++ < 0){ computeBeforeEndGroup(relationStack, resultStack); } if(!StringUtils.equals(expressDto.getType(),"GROUP")){ //TODO 进行具体单个表达式计算并获取结果 resultStack.push(expressDto.getResult()); // 将关系放入栈中 relationStack.push(expressDto.getRelation()); if(deep==0 && resultStack.size()>1){ //由于已处理小于0的deep,当前deep理论上是>=0的,0表示同等级,需要立即运算 relationOperator(relationStack, resultStack); } }else{ // 将关系放入栈中 relationStack.push(expressDto.getRelation()); } } //遍历完毕,处理栈中未进行运算的节点 while(nowDeep-- > 0){ // 这里使用 nowdeep>0 的原因是最后deep=1的关系表达式也需要进行处理 computeBeforeEndGroup(relationStack, resultStack); } if(resultStack.size()!=1){ throw new RuntimeException("表达式解析异常:解析结果数量异常解析数量:"+resultStack.size()); } return resultStack.pop(); } /** * 处理层级遗留元素 * * @param relationStack * @param resultStack */ private void computeBeforeEndGroup(Deque<String> relationStack, Deque<Boolean> resultStack) { boolean isBeginSymbol=StringUtils.equals(relationStack.peek(),"BEGIN");//防止group中仅有一个判断条件 while(!isBeginSymbol){//上一个运算符非BEGIN,说明该group中还有运算需要优先处理,正常这里应该仅循环一次 relationOperator(relationStack, resultStack); isBeginSymbol=StringUtils.equals(relationStack.peek(),"BEGIN"); } if(isBeginSymbol){ relationStack.pop();//该优先级处理完毕,将BEGIN运算符弹出 } } /** * 关系运算处理 * @param relationStack * @param resultStack */ private void relationOperator(Deque relationStack, Deque resultStack) { Boolean lastResult= resultStack.pop(); Boolean firstResult= resultStack.pop(); String relation=relationStack.pop(); if(StringUtils.equals(relation,"AND")){ resultStack.push(firstResult&& lastResult) ; return; } if(StringUtils.equals(relation,"OR")){ resultStack.push( firstResult|| lastResult); return; }else{ throw new RuntimeException("表达式解析异常:关系表达式错误"); } }
/** * 表达式:A */ @Test public void expTest0(){ ExpressDto E1=new ExpressDto().setDeep(1).setResult(false).setSeq(1).setType("CONDITION").setField("A").setRelation("BEGIN"); List<ExpressDto> list = new ArrayList(); list.add(E1); boolean re=expressProcessor(list); Assertions.assertFalse(re); } /** * 表达式:(A && B)||(C || D) */ @Test public void expTest1(){ ExpressDto E1=new ExpressDto().setDeep(1).setSeq(1).setType("GROUP").setRelation("BEGIN"); ExpressDto E2=new ExpressDto().setDeep(2).setResult(true).setSeq(2).setType("Condition").setField("A").setRelation("BEGIN"); ExpressDto E3=new ExpressDto().setDeep(2).setResult(false).setSeq(3).setType("Condition").setField("B").setRelation("AND"); ExpressDto E4=new ExpressDto().setDeep(1).setSeq(4).setType("GROUP").setRelation("OR"); ExpressDto E5=new ExpressDto().setDeep(2).setResult(true).setSeq(5).setType("Condition").setField("C").setRelation("BEGIN"); ExpressDto E6=new ExpressDto().setDeep(2).setResult(false).setSeq(6).setType("Condition").setField("D").setRelation("OR"); List<ExpressDto> list = new ArrayList(); list.add(E1); list.add(E2); list.add(E3); list.add(E4); list.add(E5); list.add(E6); boolean re=expressProcessor(list); Assertions.assertTrue(re); } /** * 表达式:A && (B || C && D) */ @Test public void expTest2(){ ExpressDto E1=new ExpressDto().setDeep(1).setResult(true).setSeq(1).setType("Condition").setField("A").setRelation("BEGIN"); ExpressDto E2=new ExpressDto().setDeep(1).setSeq(2).setType("GROUP").setRelation("AND"); ExpressDto E3=new ExpressDto().setDeep(2).setResult(false).setSeq(3).setType("Condition").setField("B").setRelation("BEGIN"); ExpressDto E4=new ExpressDto().setDeep(2).setResult(false).setSeq(4).setType("Condition").setField("C").setRelation("OR"); ExpressDto E5=new ExpressDto().setDeep(2).setResult(true).setSeq(5).setType("Condition").setField("D").setRelation("AND"); List<ExpressDto> list = new ArrayList(); list.add(E1); list.add(E2); list.add(E3); list.add(E4); list.add(E5); boolean re=expressProcessor(list); Assertions.assertFalse(re); E4.setResult(true); list.set(3,E4); re=expressProcessor(list); Assertions.assertTrue(re); E1.setResult(false); list.set(0,E1); re=expressProcessor(list); Assertions.assertFalse(re); } @Test public void expTest3(){ ExpressDto E1=new ExpressDto().setDeep(1).setResult(true).setSeq(1).setType("Condition").setField("A").setRelation("BEGIN"); ExpressDto E2=new ExpressDto().setDeep(1).setSeq(2).setType("GROUP").setRelation("OR"); ExpressDto E3=new ExpressDto().setDeep(2).setResult(true).setSeq(3).setType("Condition").setField("B").setRelation("BEGIN"); ExpressDto E4=new ExpressDto().setDeep(2).setSeq(4).setType("GROUP").setRelation("AND"); ExpressDto E5=new ExpressDto().setDeep(3).setResult(true).setSeq(5).setType("Condition").setField("C").setRelation("BEGIN"); ExpressDto E6=new ExpressDto().setDeep(3).setResult(false).setSeq(6).setType("Condition").setField("D").setRelation("OR"); List<ExpressDto> list = new ArrayList(); list.add(E1); list.add(E2); list.add(E3); list.add(E4); list.add(E5); list.add(E6); boolean re=expressProcessor(list); Assertions.assertTrue(re); } /** * 表达式:A &&(( B || C )|| (D && E)) */ @Test public void expTest4(){ ExpressDto E1=new ExpressDto().setDeep(1).setSeq(1).setType("CONDITION").setResult(true).setField("A").setRelation("BEGIN"); ExpressDto E2=new ExpressDto().setDeep(1).setSeq(2).setType("GROUP").setRelation("AND"); ExpressDto E3=new ExpressDto().setDeep(2).setSeq(3).setType("GROUP").setRelation("BEGIN"); ExpressDto E4=new ExpressDto().setDeep(3).setSeq(4).setType("CONDITION").setResult(true).setField("B").setRelation("BEGIN"); ExpressDto E5=new ExpressDto().setDeep(3).setSeq(5).setType("CONDITION").setResult(true).setField("C").setRelation("OR"); ExpressDto E6=new ExpressDto().setDeep(2).setSeq(6).setType("GROUP").setRelation("OR"); ExpressDto E7=new ExpressDto().setDeep(3).setSeq(7).setType("CONDITION").setResult(false).setField("D").setRelation("BEGIN"); ExpressDto E8=new ExpressDto().setDeep(3).setSeq(8).setType("CONDITION").setResult(false).setField("E").setRelation("AND"); List<ExpressDto> list = new ArrayList(); list.add(E1); list.add(E2); list.add(E3); list.add(E4); list.add(E5); list.add(E6); list.add(E7); list.add(E8); boolean re=expressProcessor(list); Assertions.assertTrue(re); } /** * 表达式:(A) */ @Test public void expTest5(){ ExpressDto E1=new ExpressDto().setDeep(1).setSeq(1).setType("GROUP").setRelation("BEGIN"); ExpressDto E2=new ExpressDto().setDeep(2).setResult(true).setSeq(2).setType("Condition").setField("A").setRelation("BEGIN"); List<ExpressDto> list = new ArrayList(); list.add(E1); list.add(E2); boolean re=expressProcessor(list); Assertions.assertTrue(re); E2.setResult(false); list.set(1,E2); Assertions.assertFalse(expressProcessor(list)); }Keputusan ujian:
Tuliskannya pada akhir
Kami dapati bahawa sebenarnya, fungsi Seq3 hanyalah untuk mengenal pasti permulaan kumpulan dan merekodkan perkaitan antara kumpulan dan elemen lain pada tahap yang sama, sebenarnya, pengoptimuman boleh dilakukan di sini: kami dapati bahawa setiap kali kumpulan Perhubungan prapersatuan nod pertama mestilah Begin, Deep 1. Sebenarnya, kita boleh mempertimbangkan untuk meletakkan perkaitan Kumpulan pada nod ini, dan kemudian hanya mengawal perhubungan kumpulan melalui peningkatan atau penurunan Deep In dengan cara ini, kami Medan ungkapan jenis atau kumpulan ini tidak lagi diperlukan, dan panjang tatasusunan akan dikurangkan sebagai hasilnya, tetapi saya secara peribadi berpendapat ia akan menjadi lebih menyusahkan untuk difahami. Berikut ialah idea kasar tentang transformasi, tetapi kod itu tidak akan dikeluarkan:
computeBeforeEndGroup()
, kaedah asal ialah menggunakan elemen Begin untuk membezakan sama ada Kumpulan telah diproses Sekarang ia perlu diubah untuk menentukan sama ada kedalaman simbol seterusnya adalah sama dengan kedalaman semasa, dan padamkan. logik pop timbul tentang elemen BEGIN Pembelajaran yang disyorkan: "tutorial video java"
Atas ialah kandungan terperinci Contoh pengenalan untuk melaksanakan penapis ungkapan hubungan kompleks berdasarkan Java. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!