如何实现类似';比如';java中的运算符?

如何实现类似';比如';java中的运算符?,java,sql,regex,string,wildcard,Java,Sql,Regex,String,Wildcard,我需要一个java中的比较器,它与sql“like”操作符具有相同的语义。 例如: myComparator.like("digital","%ital%"); myComparator.like("digital","%gi?a%"); myComparator.like("digital","digi%"); 应评估为真,并且 myComparator.like("digital","%cam%"); myComparator.like("digital","tal%"); 应该评估为f

我需要一个java中的比较器,它与sql“like”操作符具有相同的语义。 例如:

myComparator.like("digital","%ital%");
myComparator.like("digital","%gi?a%");
myComparator.like("digital","digi%");
应评估为真,并且

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

应该评估为false。如何实现这样一个比较器有什么想法吗?有人知道具有相同语义的实现吗?是否可以使用正则表达式执行此操作?

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

我认为java语法应该是

"digital".matches(".*ital.*");
对于单字符匹配,只需使用一个点

"digital".matches(".*gi.a.*");
要匹配实际点,请将其转义为斜线点

\.

Java字符串具有.startsWith()和.contains()方法,这些方法将为您提供大部分帮助。对于任何更复杂的问题,您必须使用正则表达式或编写自己的方法。

您可以将
'%string%'
转换为、
'string%'
转换为和
'%string'
转换为

您还应该在字符串和模式上运行
LIKE
是case instive

但不确定如何处理
“%string%other%”
,除非使用正则表达式

如果您使用的是正则表达式:


是的,这可以通过正则表达式来实现。请记住,Java正则表达式的语法与SQL的“like”不同。您将使用“
%
”,而不是“
*
”,而不是“
”,您将使用“

有点棘手的是,您还必须转义Java视为特殊的任何字符。由于您试图使其类似于SQL,我猜,
^$[]{}\
不应出现在正则表达式字符串中。但您必须将“
”替换为“
\.
“在进行任何其他替换之前。(编辑:通过在字符串周围加上“
\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);
}

我不知道贪婪问题的确切原因,但如果它对您有效,请尝试以下方法:

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);
}
public boolean-like(最终字符串str,字符串expr)
{
最终字符串[]部分=表达式拆分(“%”);
最终布尔traillingOp=expr.endsWith(“%”);
expr=“”;
对于(int i=0,l=parts.length;i1)
{
对于(int y=0,l2=p.length;y
正则表达式是最通用的。但是,一些类似的函数可以在没有正则表达式的情况下形成。e、 g

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

我能找到的每一个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();
}
publicstaticboolean-like(finalstringstr,finalstringexpr)
{
字符串regex=quotemeta(expr);
regex=regex.replace(““,”)。replace(“%”,“*?”);
Pattern p=Pattern.compile(regex,
Pattern.CASE|u不敏感| Pattern.DOTALL);
返回p.matcher(str.matches();
}
公共静态字符串quotemeta(字符串s)
{
如果(s==null)
{
抛出新的IllegalArgumentException(“字符串不能为null”);
}
int len=s.length();
如果(len==0)
{
返回“”;
}
StringBuilder sb=新StringBuilder(len*2);
对于(int i=0;i
如果您真的想使用
作为通配符,最好是将其从
quotemeta()
方法中的元字符列表中删除。替换其转义形式--
replace(“\\?”,“)--将不安全,因为原始表达式中可能存在反斜杠

这就给我们带来了真正的问题:大多数SQL风格似乎支持
[a-z]
[^j-m]
[!j-m]
形式的字符类,它们都提供了一种转义通配符的方法。后者通常通过
转义
关键字来完成,它允许您每次定义不同的转义字符。你可以想象,这让事情变得复杂了很多。转换为正则表达式可能仍然是最好的选择,但解析原始表达式将困难得多——事实上,您必须做的第一件事是将类
表达式本身的语法形式化

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

Expression exp = ExpressionFactory.likeExp("artistName", "A%");   
List startWithA = exp.filterObjects(artists); 
和接口在这里可能不适用。它们处理排序,并返回符号或0的整数。您的操作是查找匹配项并返回true/false。那不一样。

有你需要的。查找org.josql.expressions.LikeExpression.

公共静态布尔型(String toBeCompare,String by){
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;
    }
}
if(by!=null){ if(toBeCompare!=null){ if(by.startsWith(“%”)和by.endsWith(“%”){ int index=toBeCompare.toLowerCase().indexOf(by.replace(“%”,“”)。toLowerCase()); 如果(索引)
String text = "apple";
text.startsWith("app"); // like "app%"
text.endsWith("le"); // like "%le"
text.contains("ppl"); // like "%ppl%"
SELECT
CASE 
     WHEN 'StringToSearch' LIKE 'LikeSequence' THEN 'true'
     ELSE 'false'
 END test
FROM dual 
SELECT
CASE 
     WHEN 'StringToSearch' LIKE 'LikeSequence' THEN 'true'
     ELSE 'false'
END test
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, ""));
MatchingEngine m = GlobPattern.compile("dog%cat\%goat_", '%', '_', GlobPattern.HANDLE_ESCAPES);
if (m.matches(str)) { ... }
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)
}