如何实现像“LIKE”这样的SQL java中的运算符?

发布于 2024-07-22 06:10:20 字数 395 浏览 7 评论 0原文

我需要一个 java 中的比较器,它与 sql 'like' 运算符具有相同的语义。 例如:

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

应该评估为 true,并且

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

应该评估为 false。 有什么想法如何实现这样的比较器或者有人知道具有相同语义的实现吗? 这可以使用正则表达式来完成吗?

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

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

should evaluate to true, and

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

should evaluate to false. Any ideas how to implement such a comparator or does anyone know an implementation with the same semantics? Can this be done using a regular expression?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(18

晨曦÷微暖 2024-07-29 06:10:20

.* 将匹配正则表达式中的任何字符,

我认为 java 语法是

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

对于单字符匹配,只需使用一个点。

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

为了匹配实际的点,将其转义为斜杠点

\.

.* will match any characters in regular expressions

I think the java syntax would be

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

And for the single character match just use a single dot.

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

And to match an actual dot, escape it as slash dot

\.
时光暖心i 2024-07-29 06:10:20

正则表达式是最通用的。 但是,某些 LIKE 函数可以在没有正则表达式的情况下形成。 例如

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

Regular expressions are the most versatile. However, some LIKE functions can be formed without regular expressions. e.g.

String text = "digital";
text.startsWith("dig"); // like "dig%"
text.endsWith("tal"); // like "%tal"
text.contains("gita"); // like "%gita%"
空心空情空意 2024-07-29 06:10:20

是的,这可以通过正则表达式来完成。 请记住,Java 的正则表达式与 SQL 的“like”具有不同的语法。 您将使用“.*”而不是“%”,并且您将使用“.*”而不是“?”。”。

让它变得有些棘手的是,您还必须转义 Java 视为特殊的任何字符。 由于您试图使其类似于 SQL,因此我猜测 ^$[]{}\ 不应出现在正则表达式字符串中。 但在进行任何其他替换之前,您必须将“.”替换为“\\.”。 (编辑: Pattern.quote(String) 通过用“\Q”和“\E”包围字符串来转义所有内容”,这将导致表达式中的所有内容都被视为文字(根本没有通配符)。所以您肯定不想使用它。)

此外,正如 Dave Webb说,你还需要忽略大小写。

考虑到这一点,下面是它的示例:

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

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);
}
只有一腔孤勇 2024-07-29 06:10:20

我能找到的每个 SQL 参考都说“任何单个字符”通配符是下划线 (_),而不是问号 (?)。 这稍微简化了事情,因为下划线不是正则表达式元字符。 但是,由于 mmyers 给出的原因,您仍然无法使用 Pattern.quote() 。 当我之后可能想编辑正则表达式时,我有另一种方法可以转义它们。 有了这个, like() 方法就变得非常简单:

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() 方法中的元字符列表。 替换其转义形式 - replace("\\?", ".") - 并不安全,因为原始表达式中可能存在反斜杠。

这给我们带来了真正的问题:大多数 SQL 风格似乎都支持 [az][^jm][!jm] 形式的字符类,并且它们都提供了一种转义通配符的方法。 后者通常通过 ESCAPE 关键字来完成,它允许您每次定义不同的转义字符。 正如您可以想象的那样,这使事情变得相当复杂。 转换为正则表达式可能仍然是最好的选择,但解析原始表达式会困难得多 - 事实上,您要做的第一件事就是形式化类似 LIKE 的语法他们自己。

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.

转角预定愛 2024-07-29 06:10:20

要在java中实现sql的LIKE函数,你不需要正则表达式
它们可以通过以下方式获得:

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

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%"
作业与我同在 2024-07-29 06:10:20

Java 字符串有 .startsWith() 和 .contains() 方法,它们可以帮助您完成大部分工作。 对于任何更复杂的事情,您必须使用正则表达式或编写自己的方法。

Java strings have .startsWith() and .contains() methods which will get you most of the way. For anything more complicated you'd have to use regex or write your own method.

咋地 2024-07-29 06:10:20

您可以将 '%string%' 转换为 contains()'string%'startsWith()'%string"'endsWith()

您还应该运行 toLowerCase() 在字符串和模式上都为 < code>LIKE 不区分大小写。

则不确定如何处理 '%string%other%'

不过,如果您使用正则表达式,

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:

穿透光 2024-07-29 06:10:20
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;
    }
}

可能会对你有帮助

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

may be help you

我一直都在从未离去 2024-07-29 06:10:20

Apache Cayanne ORM 有一个“内存评估”,

它可能不起作用对于未映射的对象,但看起来很有希望:

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

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); 
只是偏爱你 2024-07-29 06:10:20

比较器Comparable 接口在这里可能不适用。 它们处理排序,并返回有符号或 0 的整数。您的操作是查找匹配项,并返回 true/false。 那不一样。

The Comparator and Comparable interfaces are likely inapplicable here. They deal with sorting, and return integers of either sign, or 0. Your operation is about finding matches, and returning true/false. That's different.

执笏见 2024-07-29 06:10:20

http://josql.sourceforge.net/ 有您所需要的。 查找 org.josql.expressions.LikeExpression。

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

简单爱 2024-07-29 06:10:20

我不太清楚贪婪的问题,但如果它适合你,请尝试一下:

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

i dont know exactly about the greedy issue, but try this if it works for you:

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);
}
尸血腥色 2024-07-29 06:10:20

我有一个类似的要求,经过一些修改可能会有所帮助,这里是代码:

package codeSamplesWithoutMaven;

public class TestLikeInJava {

public static void main(String[] args) {
    String fromDb = "[email protected]";
    String str1 = "*gmail*";
    String str2 = "*erick";
    String str3 = "*rick";
    String str4 = "*.com";
    String str5 = "erick*";
    String str6 = "ck@gmail*";
    System.out.println(belongsToStringWithWildcards(str1, fromDb));
    System.out.println(belongsToStringWithWildcards(str2, fromDb));
    System.out.println(belongsToStringWithWildcards(str3, fromDb));
    System.out.println(belongsToStringWithWildcards(str4, fromDb));
    System.out.println(belongsToStringWithWildcards(str5, fromDb));
    System.out.println(belongsToStringWithWildcards(str6, fromDb));
}

private static Boolean belongsToStringWithWildcards(String strToTest, String targetStr) {
    Boolean result = Boolean.FALSE;
    int type = 0; //1:start, 2:end, 3:both
    if (strToTest.startsWith("*") && strToTest.endsWith("*")) {
        type = 3;
    } else {
        if (strToTest.startsWith("*")) {
            type = 1;
        } else if (strToTest.endsWith("*")) {
            type = 2;
        }
    }
    System.out.println("strToTest " + strToTest + " into " + targetStr + " type " + type);
    strToTest = strToTest.replaceAll("[*]", "");
    System.out.println("strToTest " + strToTest + " into " + targetStr + " type " + type);
    switch (type) {
        case 1: result = targetStr.endsWith(strToTest);  
                break;
        case 2: result = targetStr.startsWith(strToTest);
                break;
        case 3: result = targetStr.contains(strToTest);
                break;
    }
    return result;
}

}

I have a similar requirement, which may help, with some modifications, here is the code:

package codeSamplesWithoutMaven;

public class TestLikeInJava {

public static void main(String[] args) {
    String fromDb = "[email protected]";
    String str1 = "*gmail*";
    String str2 = "*erick";
    String str3 = "*rick";
    String str4 = "*.com";
    String str5 = "erick*";
    String str6 = "ck@gmail*";
    System.out.println(belongsToStringWithWildcards(str1, fromDb));
    System.out.println(belongsToStringWithWildcards(str2, fromDb));
    System.out.println(belongsToStringWithWildcards(str3, fromDb));
    System.out.println(belongsToStringWithWildcards(str4, fromDb));
    System.out.println(belongsToStringWithWildcards(str5, fromDb));
    System.out.println(belongsToStringWithWildcards(str6, fromDb));
}

private static Boolean belongsToStringWithWildcards(String strToTest, String targetStr) {
    Boolean result = Boolean.FALSE;
    int type = 0; //1:start, 2:end, 3:both
    if (strToTest.startsWith("*") && strToTest.endsWith("*")) {
        type = 3;
    } else {
        if (strToTest.startsWith("*")) {
            type = 1;
        } else if (strToTest.endsWith("*")) {
            type = 2;
        }
    }
    System.out.println("strToTest " + strToTest + " into " + targetStr + " type " + type);
    strToTest = strToTest.replaceAll("[*]", "");
    System.out.println("strToTest " + strToTest + " into " + targetStr + " type " + type);
    switch (type) {
        case 1: result = targetStr.endsWith(strToTest);  
                break;
        case 2: result = targetStr.startsWith(strToTest);
                break;
        case 3: result = targetStr.contains(strToTest);
                break;
    }
    return result;
}

}

丢了幸福的猪 2024-07-29 06:10:20
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, ""));
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, ""));
三生一梦 2024-07-29 06:10:20

请查看 https://github.com/hrakaroo/glob-library-java

它是 Java 中的一个零依赖库,用于进行 glob(和类似 sql)类型的比较。 在大型数据集上,它比转换为正则表达式更快。

基本语法

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

Check out https://github.com/hrakaroo/glob-library-java.

It's a zero dependency library in Java for doing glob (and sql like) type of comparisons. Over a large data set it is faster than translating to a regular expression.

Basic syntax

MatchingEngine m = GlobPattern.compile("dog%cat\%goat_", '%', '_', GlobPattern.HANDLE_ESCAPES);
if (m.matches(str)) { ... }
捂风挽笑 2024-07-29 06:10:20

这是我对此的看法,它是用 Kotlin 编写的,但可以轻松转换为 Java:

val percentageRegex = Regex("""(?<!\\)%""")
val underscoreRegex = Regex("""(?<!\\)_""")

infix fun String.like(predicate: String): Boolean {

    //Split the text by every % not preceded by a slash.
    //We transform each slice before joining them with .* as a separator.
    return predicate.split(percentageRegex).joinToString(".*") { percentageSlice ->

        //Split the text by every _ not preceded by a slash.
        //We transform each slice before joining them with . as a separator.
        percentageSlice.split(underscoreRegex).joinToString(".") { underscoreSlice ->

            //Each slice is wrapped in "Regex quotes" to ignore all
            // the metacharacters they contain.
            //We also remove the slashes from the escape sequences
            // since they are now treated literally.
            Pattern.quote(
                underscoreSlice.replace("\\_", "_").replace("\\%", "%")
            )
        }

    }.let { "^$it$" }.toRegex().matches(this@like)
}

它可能不是这里所有解决方案中性能最高的,但它可能是最准确的。

它忽略除 % 和 _ 之外的所有其他正则表达式元字符,并且还支持使用斜杠转义它们。

This's my take on this, it's in Kotlin but can be converted to Java with little effort:

val percentageRegex = Regex("""(?<!\\)%""")
val underscoreRegex = Regex("""(?<!\\)_""")

infix fun String.like(predicate: String): Boolean {

    //Split the text by every % not preceded by a slash.
    //We transform each slice before joining them with .* as a separator.
    return predicate.split(percentageRegex).joinToString(".*") { percentageSlice ->

        //Split the text by every _ not preceded by a slash.
        //We transform each slice before joining them with . as a separator.
        percentageSlice.split(underscoreRegex).joinToString(".") { underscoreSlice ->

            //Each slice is wrapped in "Regex quotes" to ignore all
            // the metacharacters they contain.
            //We also remove the slashes from the escape sequences
            // since they are now treated literally.
            Pattern.quote(
                underscoreSlice.replace("\\_", "_").replace("\\%", "%")
            )
        }

    }.let { "^$it
quot; }.toRegex().matches(this@like)
}

It might not be the most performant of all the solutions here, but it's probably the most accurate.

It ignores all the other Regex metacharacters other than % and _ and also supports escaping them with a slash.

舞袖。长 2024-07-29 06:10:20

来自 https://www.tutorialspoint.com/java/java_string_matches.htm

import java.io.*;
public class Test {

   public static void main(String args[]) {
      String Str = new String("Welcome to Tutorialspoint.com");

      System.out.print("Return Value :" );
      System.out.println(Str.matches("(.*)Tutorials(.*)"));

      System.out.print("Return Value :" );
      System.out.println(Str.matches("Tutorials"));

      System.out.print("Return Value :" );
      System.out.println(Str.matches("Welcome(.*)"));
   }
}

from https://www.tutorialspoint.com/java/java_string_matches.htm

import java.io.*;
public class Test {

   public static void main(String args[]) {
      String Str = new String("Welcome to Tutorialspoint.com");

      System.out.print("Return Value :" );
      System.out.println(Str.matches("(.*)Tutorials(.*)"));

      System.out.print("Return Value :" );
      System.out.println(Str.matches("Tutorials"));

      System.out.print("Return Value :" );
      System.out.println(Str.matches("Welcome(.*)"));
   }
}
秋心╮凉 2024-07-29 06:10:20

好吧,这是一个有点奇怪的解决方案,但我认为仍然应该提及。

我们可以利用任何数据库中已有的现有实现,而不是重新创建类似的机制!

(唯一的要求是,您的应用程序必须有权访问任何数据库)。

每次只需运行一个非常简单的查询,根据同类比较的结果返回 true 或 false。 然后执行查询,直接从数据库中读取答案!

对于 Oracle 数据库:

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”,并设置要检查的值。

Ok this is a bit of a weird solution, but I thought it should still be mentioned.

Instead of recreating the like mechanism we can utilize the existing implementation already available in any database!

(Only requirement is, your application must have access to any database).

Just run a very simple query each time,that returns true or false depending on the result of the like's comparison. Then execute the query, and read the answer directly from the database!

For Oracle db:

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

For MS SQL Server

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

All you have to do is replace "StringToSearch" and "LikeSequence" with bind parameters and set the values you want to check.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文