多个关键字用orand包含不包含动态拼接为正则表达式和SQL查询条件

Posted 符华-

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了多个关键字用orand包含不包含动态拼接为正则表达式和SQL查询条件相关的知识,希望对你有一定的参考价值。

目录

前言

不知道大家有没有做过这种需求:在某字符串中,根据多个关键字去判断这串字符串是否满足条件。如下图:

亦或是

如果说要根据图二的关键字去数据库中查询符合条件的数据,要怎么做?是不是感觉头都大了?
暂且先不说包含、不包含,我们先来说说或、且。多个or、and是不能同时并列使用的,我们需要用括号将连续的、相同的or或者and用括号括起来。

比如图一,我们按顺序连起来就是:关键字1 and 关键字2 or 关键字3 or 关键字4 and 关键字5 or 关键字6
但是我们肯定不能直接就这么用,我们得捋一捋要把括号加在哪,哪些是并列的可以放在一个括号里的,哪些又是放在括号外面的。按照我的想法是,把连续 and 的关键字放在括号里,括号外面就是 or。
所以得出来的条件就是:(关键字1 and 关键字2) or 关键字3 or (关键字4 and 关键字5) or 关键字6

那么问题又来了,我们要怎么把这个条件转换成SQL的where条件?mysql中,包含指定字符串我们用 locate 函数,locate(‘关键字1’,字段1)>0 就表示字段1的值包含关键字1,如果是 <0 则表示不包含。

于是,我们拼出来的where条件就是:

# (关键字1 and 关键字2) or 关键字3 or (关键字4 and 关键字5) or 关键字6
( locate('关键字1',字段名)>0 and locate('关键字2',字段名)>0 ) or locate('关键字3',字段名)>0 or 
( locate('关键字4',字段名)>0 and locate('关键字5',字段名)>0 ) or locate('关键字6',字段名)>0

where条件拼出来了,那如果我觉得用locate拼的条件太长了,想用正则或者需要在java代码中,用正则表达式匹配呢?该怎么把这个条件转换成正则表达式?

包含的话,在正则中我们可以用 .* ,但这个是贪婪匹配,匹配任意次,我们只需要匹配一次就够了,所以可以用 .*? ,and 的话,直接括号并列就行,or 的话则用 | 表示。
于是得到得正则表达式就是:

((.*?关键字1.*?)(.*?关键字2.*?))|(.*?关键字3.*?)|((.*?关键字4.*?)(.*?关键字5.*?))|(.*?关键字6.*?)

校验

得到了两种查询方式的条件,那我们来验证一下,准备一张测试表:

DROP TABLE IF EXISTS `test1`;
CREATE TABLE `test1`  (
  `id` bigint NOT NULL AUTO_INCREMENT,
  `content` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '内容',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

INSERT INTO `test1` VALUES (1, '这里是测试内容关键字1内容,哈哈哈关键字2,内容内容、关键字3、测试关键字4测试;测试内容关键字5,关键字6。');
INSERT INTO `test1` VALUES (2, '生死关键字1并非我能关键字4左右,善恶也非关键字4我能独断');
INSERT INTO `test1` VALUES (3, '但我之关键字4本心将为我选择关键字5方向,我之使命将为关键字6我决断对错,纵使这世间混关键字1沌不堪,我也希望用关键字3这一身赤关键字3羽开辟曙光。');
INSERT INTO `test1` VALUES (4, '神州关键字4之地,守护者关键字4沉眠已久。关键字1铭刻编年,关键字7此刻乃是关键字4苏醒之时。奔赴关键字7远方,重燃此世之炽。');
INSERT INTO `test1` VALUES (5, '以精准完关键字5美的攻击关键字5,击退关键字6一切混沌与关键字7无序!关键字8');
INSERT INTO `test1` VALUES (6, '身披关键字7秩序之衣,穷尽关键字7武道之关键字5极。');
INSERT INTO `test1` VALUES (7, '漫漫关键字1白夜,划过天际的关键字2星辰不计关键字1其数,但旷关键字2古闪耀关键字3的明星,仅此一人。');
INSERT INTO `test1` VALUES (8, '就昆仑山搭街坊卡拉,天热广泛的撒旦发射点。关键字5');
INSERT INTO `test1` VALUES (9, '太艰苦拉关键字6萨大家发了肯定,解开了简历库进口量。');
INSERT INTO `test1` VALUES (10, '这个是测试内关键字3容呀,测试测试测试,内容内容内容这个是测试内容呀。');
INSERT INTO `test1` VALUES (11, '空手道解放昆仑山搭关键字4街坊,特我认为若i速关键字4冻i夫。解开了揭开角度来看,请问热关键字4望热望热热退热贴,烹饪例如可通过大幅高开。');
INSERT INTO `test1` VALUES (12, '哈哈哈哈关键字5哈哈,请问请问,啦啦啦关键字5啦啦啦啦,了哈哈哈哈哈哈,钱关键字5钱钱钱钱钱钱,嘎嘎嘎嘎嘎嘎嘎反反复复烦烦烦。');

验证方式一:

SELECT *
FROM test1
WHERE 
( locate('关键字1',content)>0 and locate('关键字2',content)>0 ) or locate('关键字3',content)>0 or 
( locate('关键字4',content)>0 and locate('关键字5',content)>0 ) or locate('关键字6',content)>0


验证方式二:

SELECT *
FROM test1
WHERE content REGEXP '((.*?关键字1.*?)(.*?关键字2.*?))|(.*?关键字3.*?)|((.*?关键字4.*?)(.*?关键字5.*?))|(.*?关键字6.*?)'


这么看,两种条件方式查出来的结果都是一样的。

既然这么做的思路没问题,那我们接下来要解决的就是怎么动态去拼接出这个where条件和正则表达式。

思路

1、存储方式

第一步我们先要考虑清楚,图一图二添加了多个关键字后,要以什么形式存储能更方便我们后续进行动态拼接。
我的想法是,直接把这些关键字用or、and连起来,后续用的时候也是用or、and进行分割,像这样:

# 图一:or、and也可以用其他符号代替,比如or用 | ,and用 &
关键字1and关键字2or关键字3or关键字4and关键字5or关键字6

# 图二:包含、不包含则分别用 is、no代替
is关键字1orno关键字2andno关键字3andis关键字4oris关键字5andis关键字6orno关键字7

2、实现

图一实现

我们先用 or 进行分割(数组一),每一个 or 后面都拼接上表示 “或” 的字符:正则用 | 表示或,SQL用 or 表示。

遍历数组一,对每一个遍历的元素用 and 进行分割(数组二),如果数组二长度大于1,说明有连续多个and,这时我们要在这几个连续的and最外面加上括号,把它们括起来,表示这几个条件要同时满足。

即:关键字1 and 关键字2 and 关键字3 ——> ( (关键字1) and (关键字2) and (关键字3) )

用代码实现:

/**
 * 根据关键字动态拼接正则表达式(没有包含、不包含)
 * @param keyWord 关键字
 */
public static String regByKeyWord1(String keyWord)
    String[] orSplit = keyWord.split("or");
    StringBuffer result = new StringBuffer();
    for (int i = 0; i < orSplit.length; i++) 
        String[] andSplit = orSplit[i].split("and");
        if (andSplit.length>1)
            result.append("(");
            for (int j = 0; j < andSplit.length; j++) 
                result.append("(.*?"+andSplit[j]+".*?)");
            
            result.append(")");
        else 
            result.append("(.*?"+orSplit[i]+".*?)");
        
        if (i<orSplit.length-1)
            result.append("|");
        
    
    System.out.println(result.toString());
    return result.toString();


/**
 *  根据关键字动态拼接SQL查询条件(没有包含、不包含)
 * @param keyWord 关键字
 * @param field 数据库条件字段
 */
public static String whereByKeyWord1(String keyWord,String field)
    String[] orSplit = keyWord.split("or");
    StringBuffer result = new StringBuffer();
    for (int i = 0; i < orSplit.length; i++) 
        String[] andSplit = orSplit[i].split("and");
        if (andSplit.length>1)
            result.append("(");
            for (int j = 0; j < andSplit.length; j++) 
                result.append("locate('"+andSplit[j]+"',"+field+")>0");
                if (j<andSplit.length-1)
                    result.append(" and ");
                
            
            result.append(")");
        else 
            result.append("locate('"+orSplit[i]+"',"+field+")>0");
        
        if (i<orSplit.length-1)
            result.append(" or ");
        
    
    System.out.println(result.toString());
    return result.toString();

得到的结果,和上面自己推算的条件、正则是一样的。

图二实现

图二有包含、不包含,就又要复杂一点了,特别是正则表达式!!!

因为本身对正则表达式也不熟,用的时候都是直接在网上找。单个包含或不包含就没什么难度,复杂的是多个包含不包含要一起使用,着实花了我好大一番心思。

我先把代码贴出来:

/**
 *  根据关键字动态拼接正则表达式(有包含、不包含)
 * @param keyWord 关键字
 */
public static String regByKeyWord2(String keyWord)
    String[] orSplict = keyWord.split("or");
    StringBuffer result = new StringBuffer();
    for (int i = 0; i < orSplict.length; i++) 
        String[] andSplit = orSplict[i].split("and");
        if (andSplit.length>1)
            StringBuffer sb1 = new StringBuffer();
            StringBuffer sb2 = new StringBuffer();
            result.append("(");
            int c1 = 0;
            for (int j = 0; j < andSplit.length; j++) 
                if (andSplit[j].contains("no"))
                    if (c1==0) sb1.append("((?!");
                    if (c1>0) sb1.append("|");
                    sb1.append(andSplit[j].replace("no",""));
                    c1++;
                
                if (j==andSplit.length-1 && sb1.length()>0) sb1.append(").)*");
            
            int c2 = 0;
            for (int j = 0; j < andSplit.length; j++) 
                if (!andSplit[j].contains("no"))
                    if (sb1.length()>0)
                        if (c2==0) sb2.append(sb1.toString());
                        sb2.append(andSplit[j].replace("is","")).append(sb1.toString());
                        c2++;
                    else 
                        sb2.append("(.*?"+andSplit[j].replace("is","")+".*?)");
                    
                
            
            result.append(sb2.toString());
            result.append(")");
        else 
            if (orSplict[i].contains("no"))
                result.append("((?!").append(orSplict[i].replace("no","")).append(").)*");
            else 
                result.append("(.*?"+orSplict[i].replace("is","")+".*?)");
            
        
        if (i<orSplict.length-1)
            result.append("|");
        
    
    System.out.println(result.toString());
    return result.toString();


/**
 *  根据关键字动态拼接SQL查询条件(有包含、不包含)
 * @param keyWord 关键字
 * @param field 数据库条件字段
 */
public static String whereByKeyWord2(String keyWord,String field)
    String[] orSplit = keyWord.split("or");
    StringBuffer result = new StringBuffer();
    for (int i = 0; i < orSplit.length; i++) 
        String[] andSplit = orSplit[i].split("and");
        if (andSplit.length>1)
            result.append("(");
            for (int j = 0; j < andSplit.length; j++) 
                if (andSplit[j].contains("no"))
                    result.append("locate('"+andSplit[j].replace("no","")+"',"+field+")<0");
                else 
                    result.append("locate('"+andSplit[j].replace("is","")+"',"+field+")>0");
                
                if (j<andSplit.length-1)
                    result.append(" and ");
                
            
            result.append(")");
        else 
            if (orSplit[i].contains("no"))
                result.append("locate('"+orSplit[i].replace("no","")+"',"+field+")<0");
            else 
                result.append("locate('"+orSplit[i].replace("is","")+"',"+field+")>0");
            
        
        if (i<orSplit.length-1)
            result.append(" or ");
        
    
    System.out.println(result.toString());
    return result.toString();

where条件拼接没什

以上是关于多个关键字用orand包含不包含动态拼接为正则表达式和SQL查询条件的主要内容,如果未能解决你的问题,请参考以下文章

用正则表达式怎样匹配 不包含特定字符串的字符串

正则表达式包含某字符串且不包含某些字符串

正则表达式包含某字符串且不包含某些字符串

正则表达同时包含2个甚至多个关键字 content.contains(keyword1)&&content.contains(keyword2)

正则表达式匹配指定中文字符串

判断字符串不能全部为数字的的正则表达式怎么写?