java正则表达式备忘
最近框架和爬虫上常要处理字符串匹配和替换的场景,备忘。java的正则表达式仿效了perl 5。
非贪婪模式
比如要匹配html文本中的连接,例如a href="www.abc.com/xyz/o"需要替换为a href="www.bing.com?q=o",可以如下:
static final String OSCHINA_LINK = "\"(https://www\\.abc\\.net/p/)(.+)\""; static Pattern pattern = Pattern.compile(OSCHINA_LINK); static String BING_SEARCH = "\"https://cn.bing.com/search?q=$2";
但是此时会导致第一个href="之后的文字到最后一个"之间的内容都是链接地址了,因为java正则默认是贪婪模式。要想在第一个"就结束,需要非贪婪模式,也就是加上?,如下:
static final String OSCHINA_LINK = "\"(https://www\\.abc\\.net/p/)(.+?)\""; static Pattern pattern = Pattern.compile(OSCHINA_LINK); static String BING_SEARCH = "\"https://cn.bing.com/search?q=$2";
Matcher m = pattern.matcher(param.getData().getNewsBody()); StringBuffer sb = new StringBuffer(); // 使用find()方法查找第一个匹配的对象 boolean result = m.find(); // 使用循环将句子里所有的表找出并替换为用户名.表名,再将内容加到sb里 while (result) { m.appendReplacement(sb, BING_SEARCH); // 继续查找下一个匹配对象 result = m.find(); } // 最后调用appendTail()方法将最后一次匹配后的剩余字符串加到sb里; m.appendTail(sb);
分组替换
还有一个场景是要在所有给定的关键字之前加上前缀,例如"abc,bcf,wdf"替换为"x.abc,x.bcf,x.wdf",其中关键字列表由输入给定。
这个时候就需要分组替换了,用()进行分组。如下:
String tel = "18304072984"; // 括号表示组,被替换的部分$n表示第n组的内容 tel = tel.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2"); System.out.print(tel); // output: 183****2984 String one = "hello girl hi hot".replaceFirst("(\\w+)\\s+(\\w+)", "a.$2 a.$1"); String two = "hello girl hi hot".replaceAll("(\\w+)\\s+(\\w+)", "a.$2 a.$1"); System.out.println(one); // a.girl a.hello hi hot System.out.println(two); // a.girl a.hello a.hot a.hi
命名捕获组
(?<createtablelike>create table.+ like)|(?<createtableselect>create table.+ select)
这样可以通过matcher.group(groupName)得到具体匹配的group是谁,这样便于后续分析,否则不好分析。
错误
java.lang.IllegalArgumentException: No group with name <> at java.util.regex.Matcher.getMatchedGroupIndex(Matcher.java:1316) at java.util.regex.Matcher.group(Matcher.java:572) at com.hundsun.sqlcompchecker.unifysql.UnifySqlCheckUtil.checkFeatureNotSupport(UnifySqlCheckUtil.java:467) at com.hundsun.sqlcompchecker.unifysql.UnifySqlCheckUtil$1.run(UnifySqlCheckUtil.java:171) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at java.lang.Thread.run(Thread.java:748)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
2018-06-14 spring boot完整学习指南(含各种常见问题servlet、web.xml、maven打包,spring mvc差别及解决方法)
2018-06-14 Spring-Data-Redis下实现redis连接断开后自动重连(真正解决)