복붙노트

[SQL] 어떻게 자바에서 'LIKE'연산자와 같은 SQL을 구현하는 방법?

SQL

어떻게 자바에서 'LIKE'연산자와 같은 SQL을 구현하는 방법?

I 연산자 'LIKE'는 SQL과 같은 의미를 갖는다 자바 비교기가 필요하다. 예를 들면 :

myComparator.like("digital","%ital%");
myComparator.like("digital","%gi?a%");
myComparator.like("digital","digi%");

true로 평가하고,해야

myComparator.like("digital","%cam%");
myComparator.like("digital","tal%");

false로 평가해야합니다. 모든 아이디어를 어떻게 이러한 비교를 구현하거나 사람이 동일한 의미와 구현을 알고 있나요? 이것은 정규 표현식을 사용하여 수행 할 수 있습니까?

해결법

  1. ==============================

    1.. * 정규 표현식의 모든 문자와 일치합니다

    . * 정규 표현식의 모든 문자와 일치합니다

    나는 자바 구문이있을 거라고 생각

    "digital".matches(".*ital.*");
    

    그리고 하나의 문자를 단지 하나의 점을 사용하여 일치합니다.

    "digital".matches(".*gi.a.*");
    

    그리고 실제 점과 일치하도록, 슬래시 도트로 탈출

    \.
    
  2. ==============================

    2.예,이는 정규 표현식으로 수행 할 수있다. 자바의 정규 표현식은 SQL의 "와 같은"다른 구문이 있음을 유의하십시오. 대신, 당신은 것입니다 ". *", 그리고 대신 "?", 당신은 것입니다 "." "%"의.

    예,이는 정규 표현식으로 수행 할 수있다. 자바의 정규 표현식은 SQL의 "와 같은"다른 구문이 있음을 유의하십시오. 대신, 당신은 것입니다 ". *", 그리고 대신 "?", 당신은 것입니다 "." "%"의.

    무엇 다소 까다로운 만드는 것은 당신이 특수로 자바 취급하는 모든 문자를 탈출해야한다는 것입니다. 당신은 SQL이 유사를 만들기 위해 노력하고 있기 때문에, 그 ^ $ [] {} \ 정규식 문자열에 표시되지 않아야 같은데요. 하지만 당신은 대체해야합니다 "." "\\."와 다른 교체하기 전에. (편집 : Pattern.quote (문자열) 표현에 모든 원인이됩니다 전혀 (리터럴로 더 와일드 카드를 처리하지 될 \ "Q"와 "\ E")로 문자열을 주변으로 모든 것을 탈출 그래서 당신은 확실히 돈. 't은 그것을 사용하고 싶습니다.)

    데이브 웹이 말한대로 또한, 당신은 또한 케이스를 무시해야합니다.

    염두에두고, 여기가 어떻게 보이는지의 예제는 다음과 같습니다

    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);
    }
    
  3. ==============================

    3.정규 표현식은 가장 다양한 있습니다. 그러나 일부 LIKE 함수는 정규 표현식없이 형성 될 수있다. 예를 들면

    정규 표현식은 가장 다양한 있습니다. 그러나 일부 LIKE 함수는 정규 표현식없이 형성 될 수있다. 예를 들면

    String text = "digital";
    text.startsWith("dig"); // like "dig%"
    text.endsWith("tal"); // like "%tal"
    text.contains("gita"); // like "%gita%"
    
  4. ==============================

    4.내가 찾을 수있는 모든 SQL 참조는 "단일 문자"와일드 카드는 밑줄 (_)이 아닌 물음표 말한다 (?). 단순화 것들 조금, 밑줄이 정규식 메타 문자 아니기 때문에 그. 그러나 여전히 mmyers에 의해 주어진 이유 Pattern.quote ()를 사용할 수 없습니다. 나는 나중에 편집 그들에게 할 수 있습니다 정규 표현식에 탈출 여기 다른 방법을 가지고있다. 길의 밖으로, 등 () 방법은 아주 간단하게 :

    내가 찾을 수있는 모든 SQL 참조는 "단일 문자"와일드 카드는 밑줄 (_)이 아닌 물음표 말한다 (?). 단순화 것들 조금, 밑줄이 정규식 메타 문자 아니기 때문에 그. 그러나 여전히 mmyers에 의해 주어진 이유 Pattern.quote ()를 사용할 수 없습니다. 나는 나중에 편집 그들에게 할 수 있습니다 정규 표현식에 탈출 여기 다른 방법을 가지고있다. 길의 밖으로, 등 () 방법은 아주 간단하게 :

    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();
    }
    

    당신은 정말 사용하려면? 와일드 카드를 위해, 당신의 최선의 방법은 quotemeta () 메소드에서 메타 문자의 목록에서 제거하는 것입니다. 그 탈출 양식을 교체 - 교체 ( "\\?", ".") - 원래 표현에서 백 슬래시가있을 수 있기 때문에 안전하지 않을 것입니다.

    그리고 실제 문제가 우리에게 가져다 : 대부분의 SQL 맛이 형태로 지원 문자 클래스에 [A-Z]와 같다 [^ J-m] 또는 [J-m!], 그들은 모두가 와일드 카드 문자를 탈출 할 수있는 방법을 제공합니다. 후자는 일반적으로 다른 이스케이프 문자마다 정의 할 수 있습니다 이스케이프 키워드에 의해 수행된다. 당신이 상상할 수 있듯이,이 일을 상당히 복잡하게한다. 정규식으로 변환하는 것은 여전히 ​​아마 최선의 선택이지만, 원래의 표현을 구문 분석하는 것은 더 힘들어 될 것입니다 - 사실, 당신이해야 할 첫 번째 일은 구문 LIKE와 같은 표현 자체를 공식화입니다.

  5. ==============================

    5.자바에서 SQL의 LIKE 기능을 구현하려면에서 정규 표현식이 필요하지 않습니다 그들은으로 얻을 수 있습니다 :

    자바에서 SQL의 LIKE 기능을 구현하려면에서 정규 표현식이 필요하지 않습니다 그들은으로 얻을 수 있습니다 :

    String text = "apple";
    text.startsWith("app"); // like "app%"
    text.endsWith("le"); // like "%le"
    text.contains("ppl"); // like "%ppl%"
    
  6. ==============================

    6.자바 문자열 .startsWith ()와 .contains ()를 가장 방법을 얻을 것이다 방법이있다. 아무것도 들어 더 정규식을 사용하거나 자신 만의 방법을 쓸 필요가 거라고 복잡.

    자바 문자열 .startsWith ()와 .contains ()를 가장 방법을 얻을 것이다 방법이있다. 아무것도 들어 더 정규식을 사용하거나 자신 만의 방법을 쓸 필요가 거라고 복잡.

  7. ==============================

    7.당신은) (startsWith에, '문자열 %'()와 endsWith에 '% 문자열을 "'포함에 '% 문자열 %를'돌 수 있었다 ().

    당신은) (startsWith에, '문자열 %'()와 endsWith에 '% 문자열을 "'포함에 '% 문자열 %를'돌 수 있었다 ().

    당신은 또한 LIKE는 대소 insenstive 그대로 문자열과 패턴 모두와 toLowerCase ()를 실행해야합니다.

    확실하지 비록 정규 표현식 제외 '% 문자열 % 기타 %'를 처리 할 것입니다 방법에 대해 설명합니다.

    경우에 당신은 정규 표현식을 사용하고 있습니다 :

  8. ==============================

    8.아파치 Cayanne ORM은 "에서 메모리 평가"가

    아파치 Cayanne ORM은 "에서 메모리 평가"가

    이 매핑되지 않은 개체에 대한 작동하지만 외모 약속하지 않을 수 있습니다 :

    Expression exp = ExpressionFactory.likeExp("artistName", "A%");   
    List startWithA = exp.filterObjects(artists); 
    
  9. ==============================

    9.http://josql.sourceforge.net/ 당신이 필요가 있습니다. org.josql.expressions.LikeExpression를 찾아보십시오.

    http://josql.sourceforge.net/ 당신이 필요가 있습니다. org.josql.expressions.LikeExpression를 찾아보십시오.

  10. ==============================

    10.

    public static boolean like(String toBeCompare, String by){
        if(by != null){
            if(toBeCompare != null){
                if(by.startsWith("%") && by.endsWith("%")){
                    int index = toBeCompare.toLowerCase().indexOf(by.replace("%", "").toLowerCase());
                    if(index < 0){
                        return false;
                    } else {
                        return true;
                    }
                } else if(by.startsWith("%")){
                    return toBeCompare.endsWith(by.replace("%", ""));
                } else if(by.endsWith("%")){
                    return toBeCompare.startsWith(by.replace("%", ""));
                } else {
                    return toBeCompare.equals(by.replace("%", ""));
                }
            } else {
                return false;
            }
        } else {
            return false;
        }
    }
    

    당신에게 도움이 될 수 있습니다

  11. ==============================

    11.내가 정확히 욕심이 문제에 대해 알고 있지만 그것이 당신을 위해 작동하는 경우에 이것을 시도 해달라고 :

    내가 정확히 욕심이 문제에 대해 알고 있지만 그것이 당신을 위해 작동하는 경우에 이것을 시도 해달라고 :

    public boolean like(final String str, String expr)
      {
        final String[] parts = expr.split("%");
        final boolean traillingOp = expr.endsWith("%");
        expr = "";
        for (int i = 0, l = parts.length; i < l; ++i)
        {
          final String[] p = parts[i].split("\\\\\\?");
          if (p.length > 1)
          {
            for (int y = 0, l2 = p.length; y < l2; ++y)
            {
              expr += p[y];
              if (i + 1 < l2) expr += ".";
            }
          }
          else
          {
            expr += parts[i];
          }
          if (i + 1 < l) expr += "%";
        }
        if (traillingOp) expr += "%";
        expr = expr.replace("?", ".");
        expr = expr.replace("%", ".*");
        return str.matches(expr);
    }
    
  12. ==============================

    12.비교기과 해당 인터페이스는 여기 가능성 적용 할 수 있습니다. 그들은 정렬을 처리하고, 중 기호의 반환 정수, 또는 0 귀하의 작업은 참 / 거짓의 일치를 발견하고 반환에 관한 것입니다. 그것은 달라.

    비교기과 해당 인터페이스는 여기 가능성 적용 할 수 있습니다. 그들은 정렬을 처리하고, 중 기호의 반환 정수, 또는 0 귀하의 작업은 참 / 거짓의 일치를 발견하고 반환에 관한 것입니다. 그것은 달라.

  13. ==============================

    13.

    public static boolean like(String source, String exp) {
            if (source == null || exp == null) {
                return false;
            }
    
            int sourceLength = source.length();
            int expLength = exp.length();
    
            if (sourceLength == 0 || expLength == 0) {
                return false;
            }
    
            boolean fuzzy = false;
            char lastCharOfExp = 0;
            int positionOfSource = 0;
    
            for (int i = 0; i < expLength; i++) {
                char ch = exp.charAt(i);
    
                // 是否转义
                boolean escape = false;
                if (lastCharOfExp == '\\') {
                    if (ch == '%' || ch == '_') {
                        escape = true;
                        // System.out.println("escape " + ch);
                    }
                }
    
                if (!escape && ch == '%') {
                    fuzzy = true;
                } else if (!escape && ch == '_') {
                    if (positionOfSource >= sourceLength) {
                        return false;
                    }
    
                    positionOfSource++;// <<<----- 往后加1
                } else if (ch != '\\') {// 其他字符,但是排查了转义字符
                    if (positionOfSource >= sourceLength) {// 已经超过了source的长度了
                        return false;
                    }
    
                    if (lastCharOfExp == '%') { // 上一个字符是%,要特别对待
                        int tp = source.indexOf(ch);
                        // System.out.println("上一个字符=%,当前字符是=" + ch + ",position=" + position + ",tp=" + tp);
    
                        if (tp == -1) { // 匹配不到这个字符,直接退出
                            return false;
                        }
    
                        if (tp >= positionOfSource) {
                            positionOfSource = tp + 1;// <<<----- 往下继续
    
                            if (i == expLength - 1 && positionOfSource < sourceLength) { // exp已经是最后一个字符了,此刻检查source是不是最后一个字符
                                return false;
                            }
                        } else {
                            return false;
                        }
                    } else if (source.charAt(positionOfSource) == ch) {// 在这个位置找到了ch字符
                        positionOfSource++;
                    } else {
                        return false;
                    }
                }
    
                lastCharOfExp = ch;// <<<----- 赋值
                // System.out.println("当前字符是=" + ch + ",position=" + position);
            }
    
            // expr的字符循环完了,如果不是模糊的,看在source里匹配的位置是否到达了source的末尾
            if (!fuzzy && positionOfSource < sourceLength) {
                // System.out.println("上一个字符=" + lastChar + ",position=" + position );
    
                return false;
            }
    
            return true;// 这里返回true
        }
    
    Assert.assertEquals(true, like("abc_d", "abc\\_d"));
            Assert.assertEquals(true, like("abc%d", "abc\\%%d"));
            Assert.assertEquals(false, like("abcd", "abc\\_d"));
    
            String source = "1abcd";
            Assert.assertEquals(true, like(source, "_%d"));
            Assert.assertEquals(false, like(source, "%%a"));
            Assert.assertEquals(false, like(source, "1"));
            Assert.assertEquals(true, like(source, "%d"));
            Assert.assertEquals(true, like(source, "%%%%"));
            Assert.assertEquals(true, like(source, "1%_"));
            Assert.assertEquals(false, like(source, "1%_2"));
            Assert.assertEquals(false, like(source, "1abcdef"));
            Assert.assertEquals(true, like(source, "1abcd"));
            Assert.assertEquals(false, like(source, "1abcde"));
    
            // 下面几个case很有代表性
            Assert.assertEquals(true, like(source, "_%_"));
            Assert.assertEquals(true, like(source, "_%____"));
            Assert.assertEquals(true, like(source, "_____"));// 5个
            Assert.assertEquals(false, like(source, "___"));// 3个
            Assert.assertEquals(false, like(source, "__%____"));// 6个
            Assert.assertEquals(false, like(source, "1"));
    
            Assert.assertEquals(false, like(source, "a_%b"));
            Assert.assertEquals(true, like(source, "1%"));
            Assert.assertEquals(false, like(source, "d%"));
            Assert.assertEquals(true, like(source, "_%"));
            Assert.assertEquals(true, like(source, "_abc%"));
            Assert.assertEquals(true, like(source, "%d"));
            Assert.assertEquals(true, like(source, "%abc%"));
            Assert.assertEquals(false, like(source, "ab_%"));
    
            Assert.assertEquals(true, like(source, "1ab__"));
            Assert.assertEquals(true, like(source, "1ab__%"));
            Assert.assertEquals(false, like(source, "1ab___"));
            Assert.assertEquals(true, like(source, "%"));
    
            Assert.assertEquals(false, like(null, "1ab___"));
            Assert.assertEquals(false, like(source, null));
            Assert.assertEquals(false, like(source, ""));
    
  14. ==============================

    14.https://github.com/hrakaroo/glob-library-java를 확인하십시오.

    https://github.com/hrakaroo/glob-library-java를 확인하십시오.

    그것은 비교의 글로브 (및 SQL 등) 유형을 수행하기위한 자바 제로 종속 라이브러리입니다. 큰 데이터 세트에 걸쳐 더 빨리 정규 표현식에 번역보다.

    기본 구문

    MatchingEngine m = GlobPattern.compile("dog%cat\%goat_", '%', '_', GlobPattern.HANDLE_ESCAPES);
    if (m.matches(str)) { ... }
    
  15. ==============================

    15.확인이 이상한 솔루션의 비트입니다,하지만 난 여전히 언급해야한다 생각했다.

    확인이 이상한 솔루션의 비트입니다,하지만 난 여전히 언급해야한다 생각했다.

    대신 같은 메커니즘을 다시의 우리는 어떤 데이터베이스에 이미 기존의 구현을 활용할 수 있습니다!

    (유일한 요구 사항은, 응용 프로그램이 데이터베이스에 액세스 할 수 있어야합니다).

    그냥 반환 true 또는 false가의 비교 등의 결과에 따라 것을 매우 간단한 쿼리를 할 때마다 실행합니다. 그런 다음 쿼리를 실행하고 데이터베이스에서 직접 답을 읽어!

    오라클 DB의 경우 :

    SELECT
    CASE 
         WHEN 'StringToSearch' LIKE 'LikeSequence' THEN 'true'
         ELSE 'false'
     END test
    FROM dual 
    

    MS SQL Server의

    SELECT
    CASE 
         WHEN 'StringToSearch' LIKE 'LikeSequence' THEN 'true'
         ELSE 'false'
    END test
    

    당신이해야 할 모든 바인드 매개 변수 "StringToSearch"와 "LikeSequence"를 교체하고 검사 할 값을 설정합니다.

  16. from https://stackoverflow.com/questions/898405/how-to-implement-a-sql-like-like-operator-in-java by cc-by-sa and MIT license