Kotlin:正则Regex原来这么方便

举报
二流小码农 发表于 2023/06/30 10:58:26 2023/06/30
【摘要】 Regex相对于Java的Api来说,使用起来更加的简单,如果大家在非正则的功能使用时,比如寻找,替换,是否包含等等,完全可以使用字符串自带的功能即可,如果说要实现一些较为复杂的,比如邮箱的验证,手机号的验证等等,那么Regex绝对是你的首选。

一、前言

不着急讲述Regex,我们先看一个需求,统计某个字符或字符串在整个字符串中出现的次数,举例,字符串如下:

今天是2023年6月30日,北京,天气晴,与昨天不同的是,今天格外的热,也不知道明天会怎么样,是晴天还是阴天呢,具体得到明天才能知道了。

请统计“天”字出现的次数。

实现上边的功能,我相信大家,有很多种方式,下面也举例几种:


1、循环遍历

这是最常见,也是首先能想到的。

 val content = "今天是2023年6月30日,北京,天气晴,与昨天不同的是,今天格外的热,也不知道明天会怎么样,是晴天还是阴天呢,具体得到明天才能知道了。"
 var count=0
        //遍历
 content.forEach {
     if ('天' == it) {
           count++//次数累加
        }
 }
 print(count)

打印结果

8


2、Kotlin中count操作符

 val content = "今天是2023年6月30日,北京,天气晴,与昨天不同的是,今天格外的热,也不知道明天会怎么样,是晴天还是阴天呢,具体得到明天才能知道了。"
 val count=content.count { ch -> ch == '天' }
 print(count)

打印结果

8


3、Kotlin中的filter操作符

 val content = "今天是2023年6月30日,北京,天气晴,与昨天不同的是,今天格外的热,也不知道明天会怎么样,是晴天还是阴天呢,具体得到明天才能知道了。"
 val filterContent=content.filter { ch -> ch == '天' }
 print(filterContent.length)

打印结果

8


4、使用Java中的正则

val content = "今天是2023年6月30日,北京,天气晴,与昨天不同的是,今天格外的热,也不知道明天会怎么样,是晴天还是阴天呢,具体得到明天才能知道了。"
        val pattern = Pattern.compile("天")
        val matcher = pattern.matcher(content)
        var count = 0
        while (matcher.find()) {
            count++
        }
print(count)

打印结果

8


5、使用Regex对象

val content = "今天是2023年6月30日,北京,天气晴,与昨天不同的是,今天格外的热,也不知道明天会怎么样,是晴天还是阴天呢,具体得到明天才能知道了。"
val matchResult = Regex("天").findAll(content)
print(matchResult.count())


当然了还有很多的实现方式,我们暂且举这五种,看到第五种的Regex对象实现方式,有的铁子就问了,我丝毫没有发现Regex到底有什么可取之处啊,简单吗?与Kotlin的操作符相比,简直就是小巫见大巫,毫无优点可言,别慌啊铁子,如果只是简单的文本寻找,Regex绝对没有优势,毕竟,这只是它的一个引子,冰山一角的功能,我们慢慢拉开序幕~


二、Regex方法列举

通过以上的前言,我们大致知道了,原来Regex也可以实现查找的功能,无形当中,又多了一种选择方式,除此之外,它还有那些功能呢?

构造函数

我们先看一下基本的构造函数

方法

参数类型

概述

Regex(pattern: String)

String

要匹配的正则表达式模式。

Regex(pattern: String, option: RegexOption)

String,RegexOption

根据指定的模式字符串和指定的单个选项创建正则表达式。

Regex(pattern: String, options: Set)

String,Set

根据指定的模式字符串和指定的选项集创建正则表达式

对于一个参数的构造,没什么好说的,就是一个正则表达式,这也是我们最常用的,至于后面两个,相对使用的较少,不过我们还是简单的介绍一下:

RegexOption是一个枚举类型,具体类型如下:

参数

概述

IGNORE_CASE

启用不区分大小写的匹配。大小写比较支持Unicode

MULTILINE

启用多行模式。

在多行模式中,表达式^和$分别在输入序列的行终止符或末尾之后或之前匹配。

LITERAL

启用模式的文字分析。

输入序列中的元字符或转义序列将不会被赋予特殊含义。

UNIX_LINES

启用Unix行模式。在这种模式下,只有'\n'被识别为行终止符。

COMMENTS

允许在模式中使用空格和注释。

DOT_MATCHES_ALL

启用表达式时的模式。匹配任何字符,包括行终止符。

CANON_EQ

通过规范分解实现等价。


大家可以根据不同的情况,选择对应的参数即可,至于Set,无非就是多个RegexOption。

常见方法


了解完基本的构造,我们再来看下常用的方法:

方法

参数类型

概述

find(input: CharSequence, startIndex: Int = 0)

CharSequence,Int

寻找字符串中第一个匹配的MatchResult对象,默认从索引0开始。

findAll(input: CharSequence, startIndex: Int = 0)

CharSequence,Int

字符串中所有匹配的MatchResult序列,默认从索引0开始。

containsMatchIn(input: CharSequence)

CharSequence

如果包含输入的字符就返回true。

replace(input: CharSequence, replacement: String)

CharSequence,String

和String的replace类似,第一个是输入的目标字符,第二个是替换字符。

replaceFirst(input: CharSequence, replacement: String)

CharSequence,String

替换第一个查找到的字符

matches(input: CharSequence)

CharSequence

输入字符序列是否与正则表达式匹配

matchEntire(input: CharSequence)

CharSequence

用于匹配模式中的完整输入字符


三、Regex常见方法使用举例

在上篇文章《Android:这个需求搞懵了,产品说要实现富文本回显展示》中,不知道大家是否还有印象,对于富文本的截取,我们就采用了Regex,简简单单的就实现了富文本的内容获取,当然了也简单的介绍了部分的方法。下面,我们针对第二项中的各个方法,简单做个使用案例。


1、find

find,用于寻找第一次出现的结果,比如我们要寻找某个字符串中第一次出现的数字,如下举例:

  val content = "有这样一串数字2345,还有6789,以及012,我们如何只获取数字2345呢"
  val regex = Regex("\\d+")
  val matchResult = regex.find(content)
  print(matchResult?.value)

打印结果

2345


2、findAll

findAll,顾名思义,就是寻找所有的结果,还是上面那个案例,我们改成findAll

 val content = "有这样一串数字2345,还有6789,以及012,我们如何只获取数字2345呢"
 val regex = Regex("\\d+")
 val matchResult = regex.findAll(content)
 matchResult.forEach {
      println(it.value)
 }

打印结果

2345
6789
012
2345


还有一个典型的案例,就是富文本标签的截取,这个在上篇文章举例过了,大家可以看上篇文章。


3、containsMatchIn

用于判断是否包含某个字符,和String的使用方式类似:

 val content = "二流小码农"
 val regex = Regex("农")
 val regex2 = Regex("中")
 val isContains = regex.containsMatchIn(content)
 val isContains2 = regex2.containsMatchIn(content)
 println(isContains)
 println(isContains2)

打印结果

true
false


4、replace

用于替换字符串中的相关内容:

 val content = "二流小码农"
 val regex = Regex("二")
 val replaceContent=regex.replace(content,"一")
 println(replaceContent)

打印结果

一流小码农


5、replaceFirst

用于替换字符串中第一次相符合的内容:

val content = "有这样一串数字2345,还有6789,以及012,我们如何只获取数字2345呢"
val regex = Regex("\\d+")
//把第一次出现的数字替换为字母abcd
val replaceContent=regex.replaceFirst(content,"abcd")
println(replaceContent)

打印结果

有这样一串数字abcd,还有6789,以及012,我们如何只获取数字2345呢


6、matches

用于输入的字符和目标内容是否匹配,比如用于邮箱的验证,手机号的验证等等情况:

//邮箱验证
val content = "11@qq.com"
val content2 = "11@qq"
val regex = Regex("[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+")
val matches=regex.matches(content)
val matches2=regex.matches(content2)
println(matches)
println(matches2)

打印结果

true
false

7、matchEntire

用于匹配模式中的完整输入字符。

 //匹配数字
 val regex = Regex("\\d+")
 val matchResult=regex.matchEntire("二流小码农")
 val matchResult2=regex.matchEntire("二流小码农666")
 val matchResult3=regex.matchEntire("123456")
 println(matchResult?.value)
 println(matchResult2?.value)
 println(matchResult3?.value)

打印结果

null
null
123456


四、总结

Regex相对于Java的Api来说,使用起来更加的简单,如果大家在非正则的功能使用时,比如寻找,替换,是否包含等等,完全可以使用字符串自带的功能即可,如果说要实现一些较为复杂的,比如邮箱的验证,手机号的验证等等,那么Regex绝对是你的首选。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。