scala正则表达式 findFirstIn findAllIn findFirstMatchIn findAllMatchIn Match MatchData 提取分组
项目github地址:bitcarmanlee easy-algorithm-interview-and-practice
欢迎大家star,留言,一起学习进步
0.引子
节前最后一个工作日,在编写一个简单的正则表达式的时候,卡了比较长的时间。后来总结发现,还是对正则表达式的理解不是很深刻,于是利用假期的时间,特意比较详细地看了一下正则表达式相关内容并加以记录。
1.findFirstIn findFirstMatchIn
正则表达式中常用的方法包括findFirstIn,findFirstMatchIn等类似的方法。先来看个例子,通过例子我们来看两者区别。
@Testdef test() = {val s = "你好,今天是2021年1月2日18点30分"val pattern = """今天是\d+年\d+月\d+日""".rval result1 = pattern.findFirstIn(s)println(result1)val result2 = pattern.findFirstMatchIn(s) match {case Some(data) => {println("data type is: " + data.getClass.getSimpleName)data group 0}case _ => "empty"}println(result2)}
输出结果:
Some(今天是2021年1月2日)
data type is: Match
今天是2021年1月2日
简单看下源码
/** Return an optional first matching string of this `Regex` in the given character sequence,* or None if there is no match.** @param source The text to match against.* @return An [[scala.Option]] of the first matching string in the text.* @example {{{"""\w+""".r findFirstIn "A simple example." foreach println // prints "A"}}}*/def findFirstIn(source: CharSequence): Option[String] = {val m = pattern.matcher(source)if (m.find) Some(m.group) else None}
firdFirstIn是scala.util.matching.Regex的方法。该方法的输入是一个source,source类型为CharSequence接口,最常见的实现类为字符串。
返回值为Option[String]。在我们的例子中,因为匹配上了,所以返回的值为Some[String]。
/** Return an optional first match of this `Regex` in the given character sequence,* or None if it does not exist.** If the match is successful, the [[scala.util.matching.Regex.Match]] can be queried for* more data.** @param source The text to match against.* @return A [[scala.Option]] of [[scala.util.matching.Regex.Match]] of the first matching string in the text.* @example {{{("""[a-z]""".r findFirstMatchIn "A simple example.") map (_.start) // returns Some(2), the index of the first match in the text}}}*/def findFirstMatchIn(source: CharSequence): Option[Match] = {val m = pattern.matcher(source)if (m.find) Some(new Match(source, m, groupNames)) else None}
findFirstMatchIn看源码与firdFirstIn差别不大,最大的不同在于返回的类型为Option[Match]。
2.Match MatchData
看下Match的源码
/** Provides information about a successful match. */class Match(val source: CharSequence,private[matching] val matcher: Matcher,val groupNames: Seq[String]) extends MatchData {/** The index of the first matched character. */val start = matcher.start/** The index following the last matched character. */val end = matcher.end/** The number of subgroups. */def groupCount = matcher.groupCountprivate lazy val starts: Array[Int] =((0 to groupCount) map matcher.start).toArrayprivate lazy val ends: Array[Int] =((0 to groupCount) map matcher.end).toArray/** The index of the first matched character in group `i`. */def start(i: Int) = starts(i)/** The index following the last matched character in group `i`. */def end(i: Int) = ends(i)/** The match itself with matcher-dependent lazy vals forced,* so that match is valid even once matcher is advanced.*/def force: this.type = { starts; ends; this }}
第一行注释非常关键,告诉了我们Match类最重要的作用:Provides information about a successful match。如果匹配成功,这个类会给我们提供一些匹配成功的信息,包括匹配成功的起始位置等。
Match类继承了MatchData,我们再看看MatchData的源码
trait MatchData {/** The source from which the match originated */val source: CharSequence/** The names of the groups, or an empty sequence if none defined */val groupNames: Seq[String]/** The number of capturing groups in the pattern.* (For a given successful match, some of those groups may not have matched any input.)*/def groupCount: Int/** The index of the first matched character, or -1 if nothing was matched */def start: Int/** The index of the first matched character in group `i`,* or -1 if nothing was matched for that group.*/def start(i: Int): Int.../** The matched string in group `i`,* or `null` if nothing was matched.*/def group(i: Int): String =if (start(i) >= 0) source.subSequence(start(i), end(i)).toStringelse null.../** Returns the group with given name.** @param id The group name* @return The requested group* @throws NoSuchElementException if the requested group name is not defined*/def group(id: String): String = nameToIndex.get(id) match {case None => throw new NoSuchElementException("group name "+id+" not defined")case Some(index) => group(index)}
MatchData里面用得最多,最重要的方法应该就是group了,group最大的作用,就是用来提起分组。
3.提取分组
@Testdef test() = {val s = "你好,今天是2021年1月2日18点30分"val pattern = """今天是(\d+)年(\d+)月(\d+)日""".rval result = pattern.findFirstMatchIn(s)val year = result match {case Some(data) => data group 1case _ => "-1"}println(year) // 结果为 2021}
上面的例子就是提取分组的一个典型例子,就是利用findFirstMatchIn的group方法,提取匹配结果的第一个分组,就得到了年份数据。
4.提取分组的另外一种方式
实际中提取分组还有另外一种常用方式。
@Testdef test() = {val s = "你好,今天是2021年1月2日18点30分"val pattern = """今天是(\d+)年(\d+)月(\d+)日""".rval pattern(year, month, day) = sprintln(s"year is $year.\n" +f"month is $month.\n" + raw"day is $day")}
上面的代码看起来很正常,完全没毛病,但实际上却会报错有问题,本人就是在这里被卡了很长时间。
scala.MatchError: 你好,今天是2021年1月2日18点30分 (of class java.lang.String)at com.xiaomi.mifi.pdata.common.T4.t8(T4.scala:114)at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)at java.lang.reflect.Method.invoke(Method.java:498)...
当时百思不得其解,不知道问题出在哪里。仔细看了源码以后,才明白什么情况。如果我们在IDE中点击
val pattern(year, month, day) = s
这一行查看源码,会发现调用的其实是unapplySeq方法。
def unapplySeq(s: CharSequence): Option[List[String]] = s match {case null => Nonecase _ =>val m = pattern matcher sif (runMatcher(m)) Some((1 to m.groupCount).toList map m.group)else None}
这个方法上面有一段关键的注释
/** Tries to match a [[java.lang.CharSequence]].** If the match succeeds, the result is a list of the matching* groups (or a `null` element if a group did not match any input).* If the pattern specifies no groups, then the result will be an empty list* on a successful match.** This method attempts to match the entire input by default; to find the next* matching subsequence, use an unanchored `Regex`.
这个方法默认是匹配整个输出,如果是要匹配子串,需要用unanchored这种方式。
将上面的代码稍作改动
@Testdef test() = {val s = "你好,今天是2021年1月2日18点30分"val pattern = """今天是(\d+)年(\d+)月(\d+)日""".r.unanchoredval pattern(year, month, day) = sprintln(s"year is $year.\n" +f"month is $month.\n" + raw"day is $day")}
可以得到我们预期的结果
year is 2021.
month is 1.
day is 2
5.findAllIn findAllMatchIn
findAllIn与firdFirstIn对应,findAllMatchIn与findFirstMatchIn对应,表示所有匹配结果。
先来看一个例子
@Testdef t9() = {val dateRegex = """(\d{4})-(\d{2})-(\d{2})""".rval dates = "dates in history: 2004-01-20, 2005-02-28, 1998-01-15, 2009-10-25"val result = dateRegex.findAllIn(dates)val array = for (each <- result) yield eachprintln(array)println(array.mkString("\t"))}
non-empty iterator
2004-01-20 2005-02-28 1998-01-15 2009-10-25
findAllIn的方法签名如下:
/** Return all non-overlapping matches of this `Regex` in the given character * sequence as a [[scala.util.matching.Regex.MatchIterator]],* which is a special [[scala.collection.Iterator]] that returns the* matched strings but can also be queried for more data about the last match,* such as capturing groups and start position.....def findAllIn(source: CharSequence) = new Regex.MatchIterator(source, this, groupNames)
返回的是一个MatchIterator,根据注释信息可以看出来MatchIterator是scala.collection.Iterator的一个特例,所以直接println(array)得到的信息是一个non-empty iterator。
如果我们想得到所有能匹配上的年份,则可以使用findAllMatchIn方法。该方法可以得到先得到所有的Match对象,然后再分组提取出年份即可。
@Testdef t10() = {val dateRegex = """(\d{4})-(\d{2})-(\d{2})""".rval dates = "dates in history: 2004-01-20, 2005-02-28, 1998-01-15, 2009-10-25"val result = dateRegex.findAllMatchIn(dates)val array = for(each <- result) yield each.group(1)println(array)println(array.mkString("\t"))}
最后的输出结果为
non-empty iterator
2004 2005 1998 2009
scala正则表达式 findFirstIn findAllIn findFirstMatchIn findAllMatchIn Match MatchData 提取分组相关推荐
- 【Scala 教程】Scala 正则表达式
文章作者:梦家 个人站点:dreamhomes.top 原文地址:https://dreamhomes.top/713.html 公众号ID:DreamHub 本文主要介绍 Scala 中的正则表达式 ...
- python精确匹配字符串_Python: 字符串搜索和匹配,re.compile() 编译正则表达式字符串,然后使用match() , findall() 或者finditer() 等方法...
1. 使用find()方法 >>> text = 'yeah, but no, but yeah, but no, but yeah' >>> text.find( ...
- Spark记录-Scala程序例子(函数/List/match/option/泛型/隐式转换)
object func {def main(args:Array[String]):Unit={//函数赋值给变量时, 必须在函数后面加上空格和下划线.def sayHello(name: Strin ...
- 正则表达式re.search与re.match
[时间]2019.08.07 [题目]正则表达式re.search与re.match re.search与re.match可以实现正则匹配,返回字符串中第一个符合正则表达式的字符串段,无匹配时返回No ...
- python与正则表达式(part8)--compile对象及match对象的属性方法
文章目录 compile对象属性(compile函数生成的正则表达式对象的属性) flags参数扩展 举个例子 match对象的属性方法 1.属性变量 2.属性方法 举个例子 compile对象属性( ...
- 【Scala】9、Trait、Match、CaseClass和偏函数
抽象类和接口的合体trait 1 /* * 1.trait不可以传参 * 2.类继承多个trait的时候 第一个关键字用extends 第二个用with * */ trait Read{def rea ...
- Scala入门到精通——第二十五节 提取器(Extractor)
本节主要内容 apply与unapply方法 零变量或变量的模式匹配 提取器与序列模式 scala中的占位符使用总结 1. apply与unapply方法 apply方法我们已经非常熟悉了,它帮助我们 ...
- 自然语言表达处理笔记01—— 1.正则表达式 2.文本标记化 3.词干提取和词形还原 4.中文分词
正则表达式 正则表达式使用某种预定义的模式 匹配 具有共同特征的字符串:主要用于处理字符串.完成复杂的查找.替换等要求 对字符串和特殊字符操作的逻辑公式 单个字符串描述匹配一系列复合某个句法规则的字符 ...
- 正则表达式提取html 中的网址,C#正则表达式模式从给定的字符串中提取网址 - 不是完整的html网址,也包括裸链接...
正则表达式 H3> var linkParser = new Regex(@"\b(?:https?://|www\.)\S+\b", RegexOptions.Compil ...
- 2021年大数据常用语言Scala(二十六):函数式编程 分组 groupBy
目录 分组 groupBy 定义 示例 分组 groupBy 我们如果要将数据按照分组来进行统计分析,就需要使用到分组方法 等同于SQL中的 group by的概念, 就是给数据按照指定的列进行分 ...
最新文章
- SLAM、3D vision求职经历
- 关系型数据库之Mysql备份(五)
- React native 项目进阶(redux, redux saga, redux logger)
- JS语言的基本构成、变量、数据类型
- linuxpgrepgrep_linux命令:ps pstree pgrep pidof进程管理
- 专题:生物医疗大数据
- Scope(作用域)
- 《深入理解 Spring Cloud 与微服务构建》第五章 Kubernetes
- python读写大文件 meoryerror_Python – 如何在没有MemoryError的情况下gzip大文本文件?...
- 使用jsencrypt实现参数的前端加密
- 专题九:Simulink系统仿真
- 简易学生管理系统(C语言)
- linux必学的60个命令
- 计算机无法识别psp usb设备,PSP降级导致USB连接电脑识别问题解决办法
- artDialog | 经典的网页对话框组件
- ps4如何设置虚拟服务器,PS5官方使用指南 账号设置/PS4传输数据/调整主机设定
- 一篇文章了解什么是增长黑客
- Wishbone B3总线Generic RAM写法
- 直接添加GO词云到基因表达热图上
- 如何写一篇五彩斑斓的博客.append(可爱)