首页 > 其他分享 >正则表达式和String类有关方法

正则表达式和String类有关方法

时间:2023-05-09 13:22:41浏览次数:43  
标签:字符 匹配 String 正则表达式 字符串 方法 er

正则表达式

介绍

正则表达式,又被称为规则表达式(Regular Expression,在代码中常简写为regex、regexp或RE),包括普通字符(例如:a到z之间的字符等)和特殊字符(称为元字符)。

正则表达式使用单个字符串来描述、匹配一系列匹配某个语法规则的字符串,被广泛运用于于Scala、PHP、C# 、Java、C++ 、Objective-c、Perl 、Swift、VBScript 、Javascript、Ruby以及Python等等。

目的

给定一个正则表达式(也是字符串)和另一个字符串,我们可以达到如下的目的:

  1. 判断给定的字符串是否符合正则表达式的过滤逻辑(称作“匹配”):

  2. 可以通过正则表达式,从字符串中获取我们想要的特定部分。

特点

正则表达式的特点是:

  1. 灵活性、逻辑性和功能性非常强;

  2. 可以迅速地用极简单的方式达到字符串的复杂控制。

  3. 对于刚接触的人来说,比较晦涩难懂。

由于正则表达式主要应用对象是文本,因此它在各种文本编辑器场合都有应用,小到著名编辑器EditPlus,大到Microsoft Word、Visual Studio等大型编辑器,都可以使用正则表达式来处理文本内容。

代码模板(Java代码)

/*
需求:在目标字符串中找到找到以1、2、3结尾的单词
*/

//要匹配的字符串
String str = "aa1 bb2 cc3 dd4";
//正则表达式字符串
String regStr = "[a-z]+[123]";
//将给定的正则表达式编译并赋予给Pattern类
Pattern pattern = Pattern.compile(regStr);
//构建目标字符串的正则匹配引擎
Matcher matcher = pattern.matcher(str);
//找到下一个匹配,如果没有找到,就返回false
while (matcher.find()){
    //输出匹配到的部分
	System.out.println("匹配到的内容 = " + matcher.group(0));
}

//运行结果
/*
匹配到的内容 = aa1
匹配到的内容 = bb2
匹配到的内容 = cc3
*/

在构建Matcher之后,Matcher对象中有几个元素需要注意:

变量 类型 解释 默认值
first int 匹配到的子串在原字符串的起始下标 初始值是-1。
last int 匹配到的子串在原字符串的结束下标+1,即匹配到的子串在原字符串中的下标是[first,last) 初始值是-1。
groups int[] 存放各捕获组的first和last位置。有一个默认捕获组0 每个位置的初始值是-1。

groups的解释:

有一个默认捕获组0,可以看做是整个匹配是一个大组。其他的捕获组需要再正则中声明。
各个组的起始位置和结束位置存放的地点:
起始位置:组号*2
结束位置:组号*2+1

while (matcher.find()){行打断点,进行debug调试

下一步

发现first和last,以及groups的[0]和[1]发生了改变

first和last,以及groups里面存放的数字是目标字符串的char数组下标。

matcher.group(0)
就是将分组0(起始位置groups[0]-结束位置groups[1])在原字符串进行截取。

规则

普通字符

就是正常的字符,例如a-z,0-9等等

元字符

基本元字符

-
描述
连字符,表示一定范围
例子
0-9 表示0、1、2...9
a-z 表示a、b、c...z
[]
描述
[字符列表]	表示可以接受的字符列表(默认是匹配一个,后面有别的元字符控制匹配个数)
支持'-',进行范围声明(见例子)
例子
[abc] 匹配一个字符,这个字符是a、b、c中的一个
[a12] 匹配一个字符,这个字符是a、1、2中的一个
范围声明:
[a-z] 匹配一个字符,这个字符是a、b、c...z中的一个;这里把a-z看做一个范围声明。
当然,可以进行多个范围声明
[a-z0-9] 匹配一个字符,这个字符是a、b、c...z或者是0、1、2...9中的一个;
把a-z和0-9看作是两个范围声明
[^]
描述
[^字符列表]		与[]作用是相反的,匹配任何不在字符列表中的字符(默认是匹配一个,后面有别的元字符控制匹配个数)
同样,也是支持范围声明
例子
[abc] 匹配一个字符,这个字符只要不是a、b、c,那么就匹配成功
[a-z0-9] 匹配一个字符,这个字符只要不是a、b、c...z或者是0、1、2...9中的一个,就匹配成功
.
描述
'.' 匹配任意除回车符(\r)和换行符(\n)之外的所有字符
如果只是相匹配字符'.'的话,需要进行转义。
在Java中转移:\\.
其他语言转移基本上都是:\.
例子
这个没啥例子,就是匹配任意一个除回车符(\r)和换行符(\n)之外的所有字符的含义
\\d
描述
Java是两个\,一个d;其他是一个\,一个d
匹配单个数字字符,相当于[0-9]
\\D
描述
Java是两个\,一个D;其他是一个\,一个D
是\\d的否定,匹配单个非数字字符,相当于[^0-9]
\\w
描述
Java是两个\,一个w;其他是一个\,一个w
匹配单个数字、大小写字母、下划线字符,相当于[0-9a-zA-Z_]
\\W
描述
Java是两个\,一个W;其他是一个\,一个W
是\\w的否定,匹配单个非数字、大小写字母、下划线字符,相当于[^0-9a-zA-Z_]
\\s
描述
Java是两个\,一个s;其他是一个\,一个s
匹配任何空白字符(即空格、制表符、换行符、回车符、换页符、垂直制表符),相当于[ \f\n\r\t\v]
\\S
描述
Java是两个\,一个S;其他是一个\,一个S
是\\s的否定,匹配任何非空白字符,相当于[^ \f\n\r\t\v]
(?i)
描述
不区分大小写,一般不用吧
正则表达式默认是区分大小写的
例子
(?i)abc表示abc都不区分大小写
a(?i)bc表示bc不区分大小写
a((?i)b)c表示只有b不区分大小写
|
描述
表示或

定位符

^
描述
表示起始位置
例子
^1
匹配以字符'1'开头的
$
描述
指定结束字符
例子
1$
匹配以字符'1'结尾的
\\b
描述
匹配一个单词的边界,也就是指单词和空格间的位置(即正则表达式的“匹配”有两种概念,一种是匹配字符,一种是匹配位置,这里的\\b就是匹配位置的)。
例子
“er\b”可以匹配“never”中的“er”,但不能匹配“verb”中的“er”;“\b1_”可以匹配“1_23”中的“1_”,但不能匹配“21_3”中的“1_”。
\\B
描述
与\\b相反,相当于否定。
匹配非单词边界。
例子
“er\B”能匹配“verb”中的“er”,但不能匹配“never”中的“er”。

限定符

?
描述
? 指定字符重复0次或1次 0-1次
例子
//要匹配的字符串
String str = "";
//正则表达式
String regStr = "";
+
描述
+ 表示字符重复1次到多次 1-n次
例子
“er\B”能匹配“verb”中的“er”,但不能匹配“never”中的“er”。
*
描述
* 表示字符重复0次或者多次 0-n次
例子
“er\B”能匹配“verb”中的“er”,但不能匹配“never”中的“er”。
描述
{n} 只能输入n个字符 n次
例子
“er\B”能匹配“verb”中的“er”,但不能匹配“never”中的“er”。
描述
{n,} 表示至少出现n次 >=n次
例子
“er\B”能匹配“verb”中的“er”,但不能匹配“never”中的“er”。
描述
{n,m} 指定至少n个,但不多于m个匹配 [3,5]次
例子
“er\B”能匹配“verb”中的“er”,但不能匹配“never”中的“er”。

分组

分组是用小括号来表示的,首先有一个默认分组0,即指定了整个匹配的位置。
第一个捕获分组是分组1,第二个是分组2,以此类推。

例子:
//正则表达式
String regStr = "(a+)(b+)(c*)(d+)";
这里就多了4个分组,加上默认分组0,一共有5个组。
按照顺序,(a+)是分组1,(b+)是分组2,(c+)是分组3,(d+)是分组4
在groups中起始位置和结束位置是[组号*2,组号*2+1)
使用matcher.group(int)方法获取不同组的内容
捕获分组
直接是(pattern),pattern是正则内容,按照顺序,从1开始给组进行编号

当然,也可以给组进行命名
(?<name>pattern),pattern是正则内容,name是组名

给组命名之后,获取组的方式就由两种了,一种还是按照编号(编号还是按先后顺序),另一种是通过组名获取内容matcher.group(String)
非捕获分组
(?:pattern)
(?=pattern)
(?!pattern)

默认贪婪匹配

贪婪匹配是关于数量限定符,尽可能的匹配多个字符。

非贪婪匹配:
? 在*、+、?、{n}、{n+}、{n,m}之后,匹配模式是非贪心的。尽可能短的字符串。

替换

Matcher对象的replaceAll("要替换成的字符串")
将匹配到的子串替换成"要替换成的字符串"。
这个方法是生成新的字符串返回,这个就和String特性有关了。

String与正则有关的方法

有三种方法和正则有关:

  • 匹配
  • 替换
  • 分割

匹配(matches方法)

String对象的matches方法

英文注释
@param   regex
the regular expression to which this string is to be matched
@return  {@code true} if, and only if, this string matches thegiven regular expression

翻译结果
@param正则表达式 要匹配此字符串的正则表达式
@返回 当且仅当此字符串匹配给定的正则表达式时为True


结果
你会发现实际上调用了Pattern提供的静态方法,其参数也说明了是正则表达式。

Pattern类的matches静态方法

再来看Pattern的matches静态方法,会发现还是创建了Pattern和Matcher对象,调用的是Matcher对象的matches方法。

替换(replace方法、replaceAll方法、replaceFirst方法)

String对象的replace方法(不用正则规则)

这个方法的作用:
将匹配到的全部替换,不使用正则。

代码分析:
你会发现replace方法也用了Pattern的方法,是不是也用的正则匹配?
答案是否定的,看这一句
Pattern.compile(target.toString(), Pattern.LITERAL)
关键在于在生成Pattern对象的时候除了匹配的字符串,还传了一个参数:Pattern.LITERAL
Ctrl+左键,点进去,你会发现传了这个参数,会把target.toString()当做文本字符串,没有任何特殊字符。
所以
String对象的replace方法虽然调用了Pattern的方法,但是匹配规则的文本匹配,并不是使用了正则规则。

英文注释
Enables literal parsing of the pattern.
When this flag is specified then the input string that specifies the pattern is treated as a sequence of literal characters. Metacharacters or escape sequences in the input sequence will be given no special meaning.
The flags CASE_INSENSITIVE and UNICODE_CASE retain their impact on matching when used in conjunction with this flag. The other flags become superfluous.
There is no embedded flag character for enabling literal parsing.

翻译结果
启用模式的文字解析。
当指定此标志时,指定模式的输入字符串将被视为文字字符序列。输入序列中的元字符或转义序列将没有特殊含义。
CASE_INSENSITIVE和UNICODE_CASE标志在与此标志结合使用时保留其对匹配的影响。其他的旗帜变得多余。
没有用于启用文字解析的嵌入式标志字符。

 
结果
你会发现这个就相当于一个表示,表明不使用正则规则进行匹配,而是使用普通的文本匹配。

String对象的replaceFirst方法

这个方法的作用:
只替换第一个匹配到的子串,使用正则。

代码分析:
你会发现使用的是还是Matcher对象的replaceFirst方法。
Pattern.compile(regex).matcher(this)的返回值就是Matcher对象。

String对象的replaceAll方法

这个方法的作用:
将匹配到的全部替换,使用正则。

代码分析:
你会发现使用的是还是Matcher对象的replaceAll方法。
Pattern.compile(regex).matcher(this)的返回值就是Matcher对象。

分割(split方法)

String对象的split方法

这个方法的作用:
将字符串按指定规则进行分割,返回字符串数组。
参数:
regex	匹配规则
limit	分割多少个字符串(这个方法是有重载的,重载的方法没有这个参数,重载的方法会调用这个方法,将这个参数设为0,会有特盘是不是0,0的话分割尽可能的去分割,当然还有一些特殊处理)

代码分析

代码分为两个情况:
1.通过indexOf方法,定位匹配的起始位置,然后通过substring方法进行截取,放到ArrayLIst<String>的集合里(不会使用正则引擎)。
使用的条件:
方法里自带的注释解释的很详细了:
如果正则表达式是
(1)一个字符字符串,且该字符不属于
$|()[{^?* + \ \”
或者
(2)双字符字符串,第一个字符是反斜杠和
第二个不是ASCII数字或ASCII字母。


2.调用Pattern对象的split方法,进行字符串的分割(使用正则引擎)。那面会分析Pattern对象的split方法。
使用的条件:
不满足情况1,那么就使用情况2

Pattern对象的split方法

你会发现,还是生成了Matcher对象,还是使用了Matcher对象的find方法进行匹配(正则规则)。
看这个循环:
		while(m.find()) {
            if (!matchLimited || matchList.size() < limit - 1) {
                if (index == 0 && index == m.start() && m.start() == m.end()) {
                    // no empty leading substring included for zero-width match
                    // at the beginning of the input char sequence.
                    continue;
                }
                String match = input.subSequence(index, m.start()).toString();
                matchList.add(match);
                index = m.end();
            } else if (matchList.size() == limit - 1) { // last one
                String match = input.subSequence(index,
                                                 input.length()).toString();
                matchList.add(match);
                index = m.end();
            }
        }
	你会发现是先用Matcher对象的find方法进行匹配,这时候有了匹配到的子串在原字符串中的起始位置(通过Matcher对象的start方法进行获取)。然后通过subSequence方法(这是CharSequence接口声明的方法,String类实现了该方法,实现内容是调用String的substring方法)进行截取子串。
	index是局部变量,初始化是0,每一次截取,都会调整index为匹配子串在原字符串中的结束下标+1(即index = m.end())
	在进行第一次截取的时候,如果匹配到的起始位置是原字符串的首位(即下标是0),会进行[0,0)的截取(即截取了个空字符串""),这也是有时候使用String对象的split方法的时候,返回的数组中,第一个String元素是""的原因。
	循环的次数和limit参数有关,他规定了要将原字符串最大分割成多少个子串。有个特判:matchLimited(matchLimited = limit > 0,即limit是否大于0),如果limit<=0的话,会一直进行循环,知道匹配不到为止。
	如果linmit>0的时候,在轮到最后一次截取的时候,会有特判:else if (matchList.size() == limit - 1),在这个情况,会截取剩下的所有字符。


接着往下走:
		// If no match was found, return this
        if (index == 0)
            return new String[] {input.toString()};
	这个index如果为0的话,说明循环一次都没有进行的时候,会创建一个String数组,里面就一个字符串(是和原字符串一样的字符串,但不是原字符串)

接着向下:
		// Add remaining segment
        if (!matchLimited || matchList.size() < limit)
            matchList.add(input.subSequence(index, input.length()).toString());
	如果limit<=0(其实只可能是limit==0)和limit>0且截取的字符串数量不够的时候(如果进入上面循环中的else if情况,就说明截取的字符串够了),会进行新的截取,这下是index到最后进行截取。
	这里就有个小问题:如果limit==0,或者,limit>0且截取的字符串数量不够,且最后一次匹配是在原字符串的末尾时,都会产生最后一个截取是空字符串("")的情况

接着向下:
		// Construct result
        int resultSize = matchList.size();
        if (limit == 0)
            while (resultSize > 0 && matchList.get(resultSize-1).equals(""))
                resultSize--;
	这段代码的意思是当limit==0的时候,会判断截取的字符串数组中最后一个字符串是不是空串,如果是空串就减去,这避免了上面当limit==0时有可能产生的最后一个字符串是空串的问题。这段代码在String对象的split方法中也有体现。

接着向下:
		String[] result = new String[resultSize];
        return matchList.subList(0, resultSize).toArray(result);
	这就是开始生成最终的字符串数组进行返回了(如果截取的有效字符串数量是0,会返回一个长度为0的字符串数组)

标签:字符,匹配,String,正则表达式,字符串,方法,er
From: https://www.cnblogs.com/utsaml/p/17384579.html

相关文章

  • DVD转换RMVB格式的方法
    直接将DVD转换为RMVB的方法 一.安装mpeg2解码器: 因为转换软件“Helix_Producer_Plus_9.0.1”不能直接读取DVD专用的VOB文件,所以必须安装mpeg2专用解码器“ElecardMPEG2VideoDecoderV2.0e”,安装后就可以在“Helix_Producer_Plus_9.0.1”中调用VOB文件作为源文件了。 二.安装......
  • string replace multiple items
    Doastr.replace(';',',')andthenastr.split(',')orimportrere.split(';|,',string_to_split)>>>a='Beautiful,is;better*than\nugly'>>>importre>>>re.split(......
  • input 自动填充 的解决方法总结
    方法一、form表单、input输入框设置属性autocomplete="off";<formaction="login"method="post"autocomplete="off"></form><inputautocomplete="off"> 方法二、正对有passpword的情况,chrome对aut......
  • 解决MVC4发布在IIS7后,路径无法访问.apk文件的解决方法
    随着智能手机的普及,越来越多的人使用手机上网,很多网站也应手机上网的需要推出了网站客户端,.apk文件就是安卓(Android)的应用程序后缀名,默认情况下,使用IIS作为Web服务器的无法下载此文件,那么怎么才能让IIS支持.apk文件的下载呢?IIS服务器不能下载.apk文件的原因:iis的默认MIME类型......
  • 11_父组件调用子组件方法
    父组件调用子组件的方法使用ref使用变量+watch使用中间class使用中间classbase-on-controllerfunctionreceiveController(to,from){Object.assign(to,from);}/*vue混入模式*/receiveController.mixin={methods:{receiveController}};expor......
  • C++如何实现容器的Copy/Move/Swap方法
    C++如何实现容器的Copy/Move/Swap方法1、引言目前网上有很多关于如何编写C++容器的教程,比如各种“手写STL”之类的文章和视频,但是这些教程中的容器一般都不包括allocator,比如:template<typenameT>classMyVector{...};然而我们知道标准库的容器都是有一个Allocator的模......
  • 6.螺栓,螺孔标注方法
    1.螺栓小径=0.85大径螺纹牙底画3/4圈摸的到的为实线,摸不到的为虚线 1.螺孔小径=0.85大径螺纹牙底画3/4圈摸的到的为实线,摸不到的为虚线 ......
  • Orcale-利用闪回恢复数据方法 flashback table 误删,表数据恢复到之前的某一时刻
    Orcale-利用闪回恢复数据方法原文链接:https://www.cnblogs.com/caster-xzn/p/8686376.html一.delete误删方法1:如果表结构没有改变,直接闪回整个表,具体步骤:--首先需要表闪回权限,开启行移动功能altertable表名enablerowmovement;--执行闪回恢复表数据到......
  • 高维数据惩罚回归方法:主成分回归PCR、岭回归、lasso、弹性网络elastic net分析基因数
    全文链接:http://tecdat.cn/?p=23378最近我们被客户要求撰写关于高维数据惩罚回归方法的研究报告,包括一些图形和统计输出。在本文中,我们将使用基因表达数据。这个数据集包含120个样本的200个基因的基因表达数据。这些数据来源于哺乳动物眼组织样本的微阵列实验1介绍在本文中,我......
  • 【视频】时间序列分类方法:动态时间规整算法DTW和R语言实现|附代码数据
    原文链接:http://tecdat.cn/?p=22945最近我们被客户要求撰写关于动态时间规整算法的研究报告,包括一些图形和统计输出动态时间扭曲算法何时、如何以及为什么可以有力地取代常见的欧几里得距离,以更好地对时间序列数据进行分类时间序列分类的动态时间扭曲使用机器学习算法对时间序......