使用双引号匹配字符串开头和结尾的模式,或者根本不应该使用双引号

时间:2017-09-16 01:32:56

标签: java regex

我想写一个模式匹配,它应该找到先后或后跟<,>,=,,(,)字符的字符串,但字符串在开始和结束时可能根本没有双引号或者它可能在开始和结束时都有双引号。我们也不需要关心区分大小写。我得到了下面的代码,它的工作,但它不适用于字符串开始和结束双引号的用例。      

 
    import java.util.regex.*;
    public class Test 
    {
        public static void main(String[] args) 
        {
String where = "WHERE column1>10 and Column1 in (50,60) and \"Column1\"<100"; String col = "Column1";
String patern = "(?i:[<|>|=| |(|)]"+col+"[<|>|=| |(|)])";
Pattern p = Pattern.compile(patern); Matcher m = p.matcher(where); while(m.find()) { System.out.println("Found"); } } }

输出:

实测值 结果

预期的输出是,它应该显示&#39; Found&#39;,它不适用于双引号用例。任何帮助都非常感谢。谢谢。

2 个答案:

答案 0 :(得分:0)

首先,我不明白为什么你在角色课程中使用|,但无论如何,这就是你需要的。

String where = "WHERE column1>10 and Column1 in (50,60) and \"Column1\"<100";
String affix = "[<>= ()]";
String column = "column1";

// this matches column either quoted or unquoted
String search = column + "|\"" + column + "\"";

String pattern = "(?i:" + (affix + search) + "|" + (search + affix) + ")";
Pattern p = Pattern.compile(pattern);
Matcher m = p.matcher(where);
while(m.find())
{
    System.out.println("Found");
}

答案 1 :(得分:0)

用例:我想在用户重命名列名时替换WHERE子句中的列名,这是问题的最终解决方案,对于寻找类似用例的解决方案的人来说可能会有所帮助:

/**
 * Purpose: This method checks if the user has mapped any columns info, and user has 
 * provided different target name, then this method replaces the column name in WHERE clause 
 * with user mapped target column name. 
 * Eg: 
 * Where Clause: " WHERE customer_id > 100 and "customer_id" in (200,300) and ""customer_id""_SpecailColumn" <50 
 * User mapped customer_id to target_customer_id.
 * " WHERE target_customer_id > 100 and "target_customer_id" in (200,300) and ""customer_id""_SpecailColumn" <50
 * @param table
 */
public static void replaceColumnNamesInWhereClause(Table table)
{
    if(table.getTableColumns() != null)
    {
        //affix is the set of possible characters immediately followed by column name in WHERE clause, they are - <>= ()
        String affix = "[<>= ()]";
        String where = table.getSqlWhereClause();
        logger.info("Going to replace column names in table:"+table.getName()+
                " WHERE clause with user mapped target column names, where clause before replace:"+where);
        for(TableColumn tableColumn : table.getTableColumns())
        {
            String targetColumnName = tableColumn.getTargetName();
            String columnName = tableColumn.getName();
            //If target column name is empty then skip current column and got to next column.
            if(!StringUtils.isNotEmpty(tableColumn.getTargetName()) || targetColumnName.equalsIgnoreCase(columnName))
            {
                continue;
            }
            //Get list of double quoted strings with in WHERE clause
            List<String> specialStringsInWhereCaluse = DMUtils.getDoubleQuotedStringsInWhereCaluse(where);
            String regex = "(?i:" + affix + columnName + affix + ")";
            long count = 0;
            Pattern pattern = Pattern.compile(regex);
            //Get total number of patterns found in where clause.
            count = pattern.splitAsStream(where).count();
            //Do the pattern search and replace, repeat it based on number of patterns found in original WHERE clause
            //We need to depend on number of patterns found count, instead of not Matcher.found() options, because if the WHERE has the special string
            // which has column name within that then it always says Matcher.found() as true, so it will become infinite loop.
            while(count > 0)
            {
                //If the column name has already double quotes then go to next while loop.
                if(targetColumnName.charAt(0) == '"' && targetColumnName.charAt(targetColumnName.length()) == '"')
                {
                    break;
                }
                Matcher matcher = pattern.matcher(where);
                if(matcher.find())
                {
                    String foundColumnName = where.substring(matcher.start(),matcher.end());
                    //We are have to make sure that the column name is not part of another double quoted string.
                    //eg. customer_id, but where clause is - " WHERE customer_id > 100 and ""customer_id""_SpecailColumn"
                    //In the above example "customer_id""_SpecailColumn" is the column name, so we don't want to replace this specific use case.
                    boolean replace = true;
                    for(String str: specialStringsInWhereCaluse)
                    {
                        //customer_id found in "customer_id""_SpecailColumn"
                        //We don't need to replace this use case.
                        boolean contains = str.contains(foundColumnName);
                        if(contains && str.length() != foundColumnName.length())
                        {
                            replace = false;
                            break;
                        }
                    }
                    //Replace only if column is not part of within special strings.
                    if(replace)
                    {
                        where = where.substring(0, matcher.start()+1) + tableColumn.getValidTargetName() +  where.substring(matcher.end()-1, where.length());
                    }
                }
                count --;
            }

            //This use case to find the column name with double quotes. Sometimes use put double quotes around column name in WHERE Clause.
            //we cann't make these two cases in single regular expression.
            count = 0;
            String regexDQ;
            if(columnName.charAt(0) == '"' && columnName.charAt(columnName.length()) == '"')
            {
                regexDQ = "(?i:" + affix + columnName + affix + ")";
            }
            else
            {
                regexDQ = "(?i:" + affix + "\""+ columnName +"\"" + affix + ")";
            }
            Pattern patternDQ = Pattern.compile(regexDQ);
            count = patternDQ.splitAsStream(where).count();
            //Do the pattern search and replace, repeat it based on number of patterns found in original WHERE clause
            while(count > 0)
            {
                Matcher matcherDQ = patternDQ.matcher(where);
                if(matcherDQ.find())
                {
                    String foundColumnName = where.substring(matcherDQ.start(),matcherDQ.end());
                    boolean replace = true;
                    for(String str: specialStringsInWhereCaluse)
                    {
                        //We are have to make sure that the column name is not part of another double quoted string.
                        //eg. "customer_id", but where clause is - " WHERE "customer_id" > 100 and ""customer_id""_SpecailColumn"
                        //In the above example "customer_id""_SpecailColumn" is the column name, so we don't want to replace this specific use case.
                        boolean contains = str.contains(foundColumnName);
                        if(contains && str.length() != foundColumnName.length())
                        {
                            replace = false;
                            break;
                        }
                    }
                    //Replace only if column is not part of within special strings.
                    if(replace)
                    {
                        where = where.substring(0, matcherDQ.start()+2) + tableColumn.getValidTargetName() +  where.substring(matcherDQ.end()-2, where.length());
                    }
                }
                count--;
            }
        }
        table.setSqlWhereClause(where);
        logger.info("Column names in table:"+table.getName()+
                " WHERE clause replaced with user mapped target column names, where clause after replace:"+where);
    }
}
/**
 * Purpose: This method takes the WHERE clause and identified if there are any double quoted strings
 * are present with in the WHERE clause, it does not consider "" as a string as Teradata considered 
 * "" as " in object name.
 * @param whereCaluse
 * @return
 */
public static List<String> getDoubleQuotedStringsInWhereCaluse(String whereCaluse)
{
    List<String> list = new ArrayList<String>();
    boolean stringStarted = false, stringEnded = false;
    String quotedString = "";
    for(int i=0; i<whereCaluse.length(); i++)
    {
        if(whereCaluse.charAt(i) == '"')
        {
            if(!stringStarted)
            {
                stringStarted = true;
            }
            else if(!(whereCaluse.charAt(i-1) == '"'))
            {
                stringEnded = true;
            }

        }
        if(stringStarted && !stringEnded)
        {
            quotedString = quotedString + whereCaluse.charAt(i);
        }
        if(stringEnded)
        {
            quotedString = quotedString + whereCaluse.charAt(i);
            list.add(quotedString);
            stringStarted = false; stringEnded = false;
        }
    }

    return list;
}