How to implement a SQL like 'LIKE' operator in java?

后端 未结 15 1394
你的背包
你的背包 2020-11-29 03:12

I need a comparator in java which has the same semantics as the sql \'like\' operator. For example:

myComparator.like(\"digital\",\"%ital%\");
myComparator.l         


        
相关标签:
15条回答
  • 2020-11-29 04:01

    Yes, this could be done with a regular expression. Keep in mind that Java's regular expressions have different syntax from SQL's "like". Instead of "%", you would have ".*", and instead of "?", you would have ".".

    What makes it somewhat tricky is that you would also have to escape any characters that Java treats as special. Since you're trying to make this analogous to SQL, I'm guessing that ^$[]{}\ shouldn't appear in the regex string. But you will have to replace "." with "\\." before doing any other replacements. (Edit: Pattern.quote(String) escapes everything by surrounding the string with "\Q" and "\E", which will cause everything in the expression to be treated as a literal (no wildcards at all). So you definitely don't want to use it.)

    Furthermore, as Dave Webb says, you also need to ignore case.

    With that in mind, here's a sample of what it might look like:

    public static boolean like(String str, String expr) {
        expr = expr.toLowerCase(); // ignoring locale for now
        expr = expr.replace(".", "\\."); // "\\" is escaped to "\" (thanks, Alan M)
        // ... escape any other potentially problematic characters here
        expr = expr.replace("?", ".");
        expr = expr.replace("%", ".*");
        str = str.toLowerCase();
        return str.matches(expr);
    }
    
    0 讨论(0)
  • 2020-11-29 04:01

    You could turn '%string%' to contains(), 'string%' to startsWith() and '%string"' to endsWith().

    You should also run toLowerCase() on both the string and pattern as LIKE is case-insenstive.

    Not sure how you'd handle '%string%other%' except with a Regular Expression though.

    If you're using Regular Expressions:

    • Quote the string before you replace the % characters
    • Watch out for escaped characters in the LIKE String
    0 讨论(0)
  • 2020-11-29 04:03

    Every SQL reference I can find says the "any single character" wildcard is the underscore (_), not the question mark (?). That simplifies things a bit, since the underscore is not a regex metacharacter. However, you still can't use Pattern.quote() for the reason given by mmyers. I've got another method here for escaping regexes when I might want to edit them afterward. With that out of the way, the like() method becomes pretty simple:

    public static boolean like(final String str, final String expr)
    {
      String regex = quotemeta(expr);
      regex = regex.replace("_", ".").replace("%", ".*?");
      Pattern p = Pattern.compile(regex,
          Pattern.CASE_INSENSITIVE | Pattern.DOTALL);
      return p.matcher(str).matches();
    }
    
    public static String quotemeta(String s)
    {
      if (s == null)
      {
        throw new IllegalArgumentException("String cannot be null");
      }
    
      int len = s.length();
      if (len == 0)
      {
        return "";
      }
    
      StringBuilder sb = new StringBuilder(len * 2);
      for (int i = 0; i < len; i++)
      {
        char c = s.charAt(i);
        if ("[](){}.*+?$^|#\\".indexOf(c) != -1)
        {
          sb.append("\\");
        }
        sb.append(c);
      }
      return sb.toString();
    }
    

    If you really want to use ? for the wildcard, your best bet would be to remove it from the list of metacharacters in the quotemeta() method. Replacing its escaped form -- replace("\\?", ".") -- wouldn't be safe because there might be backslashes in the original expression.

    And that brings us to the real problems: most SQL flavors seem to support character classes in the forms [a-z] and [^j-m] or [!j-m], and they all provide a way to escape wildcard characters. The latter is usually done by means of an ESCAPE keyword, which lets you define a different escape character every time. As you can imagine, this complicates things quite a bit. Converting to a regex is probably still the best option, but parsing the original expression will be much harder--in fact, the first thing you would have to do is formalize the syntax of the LIKE-like expressions themselves.

    0 讨论(0)
  • 2020-11-29 04:03

    Apache Cayanne ORM has an "In memory evaluation"

    It may not work for unmapped object, but looks promising:

    Expression exp = ExpressionFactory.likeExp("artistName", "A%");   
    List startWithA = exp.filterObjects(artists); 
    
    0 讨论(0)
  • 2020-11-29 04:05

    http://josql.sourceforge.net/ has what you need. Look for org.josql.expressions.LikeExpression.

    0 讨论(0)
  • 2020-11-29 04:06

    To implement LIKE functions of sql in java you don't need regular expression in They can be obtained as:

    String text = "apple";
    text.startsWith("app"); // like "app%"
    text.endsWith("le"); // like "%le"
    text.contains("ppl"); // like "%ppl%"
    
    0 讨论(0)
提交回复
热议问题