当前位置: 首页 > 科技观察

精通正则表达式,就看这篇文章

时间:2023-03-19 01:51:11 科技观察

大家好,我是北君。新年快乐,工作顺利。关于正则表达式,不知道大家有没有这种感觉。总可以根据自己的需要写一些,但是不执行总觉得不靠谱。今天,让我们简单了解一下正则表达式。平时用正则表达式做什么,大部分是检查一些字符串?下面有几个问题,不妨试试看能不能通过正则表达式来解决?检查密码是否包含字母、数字、特殊字符(!@#¥%^&),长度为6~12位。使用数字12345678(每3位一个)的货币格式,最终效果:12,345,678替换一段文本占位字符部分(如${}中包含的内容),类似于ES6中的模板语法定义正则表达式,又称正则表达式,(RegularExpression,在代码中常缩写为regex、regexp或RE),是一种文本模式,包括普通字符(例如a和z之间的字母)和特殊字符(称为“元字符”),是计算机科学中的一个概念。正则表达式使用单个字符串来描述和匹配一系列符合某种语法规则的字符串,通常用于检索和替换符合某种模式(规则)的文本。正则表达式是字符串运算的逻辑公式。就是利用预先定义好的一些特定的字符,以及这些特定字符的组合,组成一个“规则串”。这个“规则字符串”是用来表达字符串的过滤逻辑。Function回顾上面三个问题,我们使用正则化基本完成了类似的任务。从功能上,我们可以将其分为:Match检查目标字符串是否匹配指定的规则。比如密码强度验证、手机号验证、URL地址验证等,一般都是用来验证一个字符串的格式。Replace根据规则替换字符串的内容。比如将一段文本中的特殊字符替换为空字符串,主要是根据指定规则替换截取文本内容,在字符串中找到特定规则的片段。可用于提取目标字符串中符合规则的片段结构。正则表达式由普通字符和元字符组成。其中,普通字符包括0-9、a-z、A-Z及各种符号;元字符就像+?\d\s,具有特殊含义。Character普通字符字符描述[ABC]匹配[...]范围内的所有字符[^ABC]匹配不在[...]范围内的所有字符[A-Z]匹配A-Z范围内的字符[a-d[m-p]]匹配a-d或Them-p区间[a-z&&[^bc]]内的字符匹配a-z区间内的字符且不包含bc非打印字符字符描述\cx匹配x指定的控制字符。例如,\cM匹配Control-M或回车。x的值必须是A-Z或a-z之一。否则,将c视为文字'c'字符。\f匹配换页符。等同于\x0c和\cL。\n匹配换行符。等同于\x0a和\cJ。\r匹配回车符。等同于\x0d和\cM。\s匹配任何空白字符,包括空格、制表符、换页等等。等同于[\f\n\r\t\v]。请注意,Unicode正则表达式将匹配全角空格。\S匹配任何非空白字符。等同于[^\f\n\r\t\v]。\t匹配制表符。等同于\x09和\cI。\v匹配垂直制表符。等同于\x0b和\cK。特殊字符特殊字符串说明^匹配输入字符串的开头,除非它用在方括号表达式中。当这个符号用在方括号表达式中时,表示不接受方括号表达式中的字符集。要匹配^字符本身,请使用^。$匹配输入字符串的末尾。也匹配或如果设置了RegExp对象的多行属性。要匹配字符本身,请使用$。\将下一个字符标记为特殊字符、文字字符、反向引用或八进制转义字符。例如,“n”匹配字符“n”。'\n'匹配换行符。序列'\'匹配“”,'('匹配“(”。*匹配前面的子表达式零次或多次。要匹配*字符,请使用*。+匹配前面的子表达式一次或多次。要匹配a+字符,使用+..匹配除换行符\n之外的任何单个字符。要匹配.,使用..?匹配前面的子表达式零次或一次,或指定一个非贪婪限定符。匹配?字符,使用?。[标记括号表达式的开始。要匹配[,使用[。项之间的选择。要匹配|,使用\|。()标记子表达式的开始和结束。可以捕获子表达式供以后使用。要匹配这些字符,请使用(和)。qualifierqualifierdescription*与前面的子表达式匹配零次或多次。例如,zo*将匹配“z”和“zoo”。*等同于{0,}。+与前面的子表达式匹配一次或多次。例如,zo+匹配“zo”和“zoo”,但不匹配“z”。+等同于{1,}。?零次或一次匹配前面的子表达式。例如,做(或)?匹配"do"、"does"和"doxy"中的"do"。?相当于{0,1}。{n}n是一个非负整数。恰好匹配n次。例如,o{2}不会匹配“Bob”中的o,但会匹配“food”中的两个o{n,}n,其中n是一个非负整数。至少匹配n次。例如,o{2,}不会匹配“Bob”中的o,但会匹配“foooood”中的所有o。o{1,}等同于o+。o{0,}等同于o*。{n,m}m和n都是非负整数,其中n<=m。最少匹配n次,最多匹配m次。例如,o{1,3}将匹配“fooooood”中的前三个o。o{0,1}等同于o?。请注意,逗号和两个数字之间不能有空格。定位器字符描述^匹配输入字符串的开始位置$匹配输入字符串的结束位置。\b匹配单词边界,单词和空格之间的位置。\B匹配非单词边界。规则匹配贪心匹配、惰性匹配贪心匹配和惰性匹配影响被量词修饰的子表达式的匹配行为。贪心模式在整个表达式匹配成功的前提下尽可能匹配,而非贪婪模式在整个表达式匹配成功的前提下尽可能少匹配(惰性模式:在限定符后加?)源字符串:...

hello
Regex
!
..贪婪模式:
.*
->
hello
Regex
!
惰性模式:
.*?
->
hello
Regex
当回溯正则表达式与目标字符串匹配时,它会从左到右逐个测试表达式的组成部分,看是否能找到匹配项。遇到量词时,需要决定何时尝试匹配更多的字符。遇到分支时,必须选择可用选项之一来尝试匹配。每当正则表达式做出类似的决定时,如果有必要,记录其他的选择,这样如果匹配不成功,可以追溯到上次的决定点,然后重新匹配。我们可以简单理解为正则匹配有多个case时,失败后会有重试机制,直到所有case都失败后才会失败。请注意,有时这是一个非常昂贵的正则化:ab{1,3}c源字符串:abc第一个匹配:a匹配到第二个匹配:b{1,3}匹配到b第三个匹配:b{1,3}匹配c、因为贪心模式,尽可能多的匹配,当匹配到b时,继续,遇到c时,匹配失败,回溯上次成功的状态。第四次匹配:b{1,3}匹配到b第五次匹配:c匹配到c,批处理成功为了减少回溯带来的性能问题,尽量明确要匹配的目标字符并避免贪心模式,例如使用b{1,3}?分组、引用和断言分组:语法()使用括号从左到右,从外到内依次对分组进行编号使用(?)来显示和分配分组名称Assert非分组示例:(A)(B(C))会对应多个组:0:(A)(B(C))1:(A)2:(B(C))3:(C)参考:syntax\groupnumbervia\group编号引用分组减少重复//引用主要是为了减少输入,但要注意正确引用Pattern.compile("(###).*(\\1)").matcher("###thisiscontent###")Assertions:(?=pattern)零宽正先行断言(lookahead)(?!pattern)零宽负先行断言(negativelookahead)(?<=pattern)零宽正先行断言(positiveLook-behind)(?>>{}",compile.matcher(password).matches());}问题2,也是借助断言,实现了字符串的查找,最终实现了替换。当然,我们替换的不是字符,而是匹配位置@Testpublicvoidscientific(){Stringnumber="123456789";Stringresult=number.replaceAll("(?=\\B(\\d{3})+$)",",");log.info(">>{}",结果);}问题3,通过分组实现字符串分片查找,通过变量context重新组合字符串@TestpublicvoidreplaceHolder(){Mapcontext=newHashMap<>();context.put("公司","北方");context.put("项目","blob");context.put("模型","正则表达式");Stringpackages="com.{company}.{project}.{model}.*";模式pattern=Pattern.compile("(\\{[^}]*\\})");匹配器匹配器=模式。匹配器(包);StringBuffer结果=newStringBuffer();while(matcher.find()){Stringgroup=matcher.团体();字符串键=组。substring(1,group.length()-1);matcher.appendReplacement(result,context.getOrDefault(key,""));}matcher.appendTail(结果);log.info(result.toString());}工具库https://www.runoob.com/regexp/regexp-operator.html扩展知识NFA引擎DFA引擎结语正则表达式是一种简单、强大且常用的技术。基本上所有的编程语言都有其相关的实现和支持,所以你需要多了解正则表达式。实现原则和编写规范非常重要。本文主要通过几个简单的例子来介绍正则表达式的作用以及一些基本的结构和功能。我希望它能让你更好地理解正则表达式。