我需要Java中的比较器,该比较器的语义与sql"赞"运算符相同。

例如:

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

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

myComparator.like("digital","digi%");

应该评估为真,并且

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

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

应该评估为假。 关于如何实现这样的比较器的任何想法,或者有人知道具有相同语义的实现吗? 可以使用正则表达式吗?

请参阅Apache Cayenne项目中的RegexUtil#sqlPatternToRegex(String)。

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

我认为Java语法是

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

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

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

为了匹配实际的点,请将其转为斜线点

\.

是的,谢谢!但是,如果单词inst如此简单,例如"%dig%",并且字符串需要一些escping键?已经有东西了吗?怎么样 ? ?

我为问号运算符编辑了答案。我对您的其余评论感到有些困惑。您是说要使用sql语法显示字符串,并且要按原样对其求值?如果是这种情况,我认为您将需要手动替换为sql语法。

如果用作搜索模式的字符串也包含诸如(或)的分组字符怎么办?其他字符怎么需要转义?

我认为这取决于您允许多少选择。

只是要注意。*是贪婪的(。*?可能更合适)。我不认为正则表达式中的。*与SQL中的%语义完全相同。

很好,请参阅以下问题进行爆炸stackoverflow.com/questions/255815/

是的,可以使用正则表达式来完成。请记住,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);

}

是否存在一种方法,可以在Java正则表达式中转义具有特殊含义的每个字符?

是的,Pattern.quote(java.sun.com/javase/6/docs/api/java/util/regex/)可以做到。出于某种原因,我认为这可能会导致问题,但是现在我不知道为什么不将其包括在答案中。

哦,是的,现在我记得了。这是因为 ?是一个特殊的正则表达式字符,因此在替换它之前将其转义。我想我们可以改为使用Pattern.quote,然后使用expr = expr.replace(" \?","。");

第三行应显示为replace(".","\\.");

你是对的。我应该在发布之前先在点上对其进行测试。

您还可以添加expr = expr.replaceAll("(?,因为"\_"可以在SQL中转义,因此在这种情况下不应替换为"."。 (对于一个字符,我使用了_而不是?。)

另外,对于%,此替换会更好:expr = expr.replaceAll("(?

正则表达式是最通用的。但是,某些LIKE函数可以不使用正则表达式而形成。例如

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

}

如果您真的想对通配符使用?,那么最好的选择是在quotemeta()方法中将其从元字符列表中删除。替换其转义的格式replace("\\?",".")并不安全,因为原始表达式中可能存在反斜杠。

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

是的,你是对的。我比我更喜欢您的解决方案。

如果(s == null)抛出新的IllegalArgumentException("字符串不能为null");否则if(s.isEmpty())返回";

要在Java中实现sql的LIKE函数,您不需要在

它们可以通过以下方式获得:

String text ="apple";

text.startsWith("app"); // like"app%"

text.endsWith("le"); // like"%le"

text.contains("ppl"); // like"%ppl%"

这本质上只是多年前发布的现有答案的重复。

该答案已经发布

您可以将'%string%'更改为contains(),将'string%'更改为startsWith(),将'%string"'更改为endsWith()。

您还应该在字符串和模式上同时运行toLowerCase(),因为LIKE是区分大小写的。

除了使用正则表达式外,不确定如何处理'%string%other%'。

如果您使用正则表达式:

在替换%字符之前,请给字符串加引号

注意LIKE字符串中的转义字符

什么是abot"%this%string%"?分割%符号,遍历数组,然后检查每个条目?我认为这可以做得更好...

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;

}

}

可能会帮助你

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

Apache Cayanne ORM具有"内存中的评估"

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

Expression exp = ExpressionFactory.likeExp("artistName","A%");

List startWithA = exp.filterObjects(artists);

您知道休眠是否支持此功能吗?我的意思是,使用这样的表达式过滤当前内存中的对象?

Java字符串具有.startsWith()和.contains()方法,它们将使您获得更多收益。对于更复杂的事情,您必须使用正则表达式或编写自己的方法。

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

欢迎您为运营商建议一个更好的名称。我不喜欢批评家,没有改进的建议,顺便说一句。

我不完全了解贪婪的问题,但是如果它对您有用,请尝试以下操作:

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

}

您的内部split()和循环会替换任何?带点的顺序-我不明白。为什么要选择该序列,而只用一个点代替它,就像一个单独的问号?

它取代了?与。因为?是单个任意字符的占位符。我知道 \\\?看起来很奇怪,但是我进行了测试,并且对于我的测试来说似乎可行。

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++;// <<

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

好的,这是一个奇怪的解决方案,但我认为仍然应该提到它。

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

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

每次只运行一个非常简单的查询,根据同类比较的结果返回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",并设置要检查的值。

java like a_如何在Java中实现类似“ LIKE”运算符的SQL?相关推荐

  1. 如何在 Linux 中使用类似智能手机外观的 Conky 天气插件

    如何在 Linux 中使用类似智能手机外观的 Conky 天气插件 智能手机都拥有一些平滑地融入手机外观的天气小插件,现在幸亏有了 Flair Weather Conky,你便可以在你的 Linux ...

  2. vue 递归创建菜单_如何在Vue中创建类似中等的突出显示菜单

    vue 递归创建菜单 by Taha Shashtari 由Taha Shashtari 如何在Vue中创建类似中等的突出显示菜单 (How to Create a Medium-Like Highl ...

  3. java发送gmail_如何在Gmail中轻松通过电子邮件发送人群

    java发送gmail Mailing lists are an old tool in the email arsenal, but their implementation in Gmail is ...

  4. cmd中加载java源文件_如何在cmd中编译和运行java源文件

    如何在cmd中编译和运行java源文件 首先写一个名为HelloWorld.java的java源文件,存储在如C:/java/src的地址,我们再假设待会要存储的位置是C:/java/bin,则我们做 ...

  5. java 联合_如何在java中进行联合,相交,区分和反向数据

    我想在Java中有联合,相交,差异和反向操作. 首先我有2个ArrayList< Integer> a = [0,2,4,5,6,8,10] b = [5,6,7,8,9,10] 一个工会 ...

  6. java 运费_如何在Java中创建运费成本计算器

    我正在创建计算器来计算运费.代码是这样的:如何在Java中创建运费成本计算器 class ShippingCalc { public static void main(String[] args) { ...

  7. java 合并pdf,如何在Java中合并PDF

    如何在Java中合并PDF 为小型企业和大型企业,保持 您的 重要 文件, 组织将提高您的工作流程,并成倍增长你的组织的工作效率. PDF文档由于其接受的输入格式的类型的安全性和灵活性,通常是共享大量 ...

  8. java 关闭jpanel_如何在Java中关闭Jpanel程序

    我正在制作一个Java游戏,我需要一些关于如何操作的建议.如何在Java中关闭Jpanel程序 目前我使用2个不同的.java文件来制作游戏.我有一个扩展JFrame的主程序,我调用扩展JPanel的 ...

  9. java 二叉查找树_如何在Java中实现二叉搜索树( binary search tree)?

    二叉搜索树或BST是一种流行的数据结构,用于保持元素的顺序.二叉搜索树是二叉树,其中左子节点的值小于或等于父节点,右子节点的值大于或等于父节点.由于它是二叉树,它只能有0,1或2个子节点.二叉搜索树之 ...

最新文章

  1. JavaScript学习(十三)---RegExp对象
  2. 端口复用及其实现分析[Google Patch]
  3. CTFshow php特性 web132
  4. composer update 的时候提示the requested PHP extension pcntl is missing from your system.的方法处理
  5. Docker入门-构建第一个Java程序
  6. 地址解析协议 (ARP) 是什么
  7. (android之sqlite三)单机Sqlite数据库
  8. 计算机网络——数据链路层
  9. 「斑愿称为最肝」小狮子前端知识食谱 / 生日之际,好运分享 / 秋招和你手摸手入大厂【史上最全指北】 | CSDN技术征文
  10. erroe C1083:无法打开包括文件(源文件)
  11. 科学记忆单词---麦克米伦
  12. 浏览器是先执行js还是先加载HTML,在HTML中使用JavaScript(浏览器对js的加载机制分析)...
  13. Cell:代谢组学肠道微生物群介导生酮饮食的抗癫痫作用
  14. Debian etch 基本系统 initial ram disk 的分析
  15. 探店通系统,短视频矩阵源码,抖音矩阵系统,look
  16. Resistors in Parallel(Gym - 102028E 2018 ICPC 焦作E题 大数+规律C++版)
  17. 2016-3-14恬淡努力的一天
  18. 搭建redis集群-(伪分布式)
  19. 安卓系统应用程序开发!华为Android面试真题解析,内含福利
  20. 数据分析可视化11 案例 5:门店盈利能力对比图设计

热门文章

  1. ​【文末有福利】为何美国的科研既能得诺贝尔奖,又能产生高科技产品?
  2. Nature150岁生日:盘点史上十大重磅论文,中国13篇文章登上封面!
  3. 总奖池25万!百度AI Studio人工智能竞赛火热报名中
  4. php 向服务器发放请求,PHP客户端向服务器端发送请求并向远程服务器发送服务器端请求...
  5. GC算法-引用计数法
  6. NS2:undefined reference to `xxx' collect2: error: ld returned 1 exit status
  7. spring中aop事务
  8. AliRTC 开启视频互动 “零计算” 时代
  9. 5分钟入门Lindorm SearchIndex
  10. 线上流量越发昂贵,如何通过裂变营销实现业务增长?