Java-9_2-正则表达式与序列化
本篇将讨论正则表达式和对象序列化的内容。
A. 正则表达式
正则表达式就是通过定义、使用一些特殊含义的字符,以一个字符串来表示一类具有同样规律的字符串。这里首先介绍 Java 中正则表达式中的特殊字符,其次,介绍 Java 中利用正则表达式对字符串进行匹配的方式。
a. 基本语法
在 Java 的正则表达式中,. * + ? { | ( ) [ \ ^ $
具有特殊含义。
.
匹配任意字符;*
前面的字符重复任意次;+
前面的字符重复1次或更多次;?
前面的字符出现 0 或 1 次;(e.g.be+s?
与 “bee”, “be”, “bees” 匹配)|
表示 或,例如 “.(oo|ee)f”, 可以匹配 “beef” 或 “woof”。- Character class, 是用 “[]” 括起来的内容,例如,
"[0-9]"
。 其中 “-“ 表示 从 左边字符 到右边字符的范围内的所有字符。 - predefined character class, 例如 “\d” (digits), “\p{sc}” Unicode 中的货币符号。(java 中的其他特殊含义字符集,参考书中表格p311)
^
,$
分别匹配字符串的开头和结尾;\
, 在特殊符号前加\
, 表明不使用他们的特殊含义。\Q
,\E
包裹字符串,表明内部内容都是字符串内容,没有特殊含义。例如 “\Q(\$0.99)\E”, 表示字符串 “(\$0.99)”。
b. 寻找匹配值
判定字符串是否与正则表达式匹配有多种方式,参考下面的代码。
1 | // 通过 Pattern 的静态方法 matches() |
如果想寻找 一段字符串/一个文件中 中所有与正则表达式相匹配的内容,可以通过下面的方式进行:
1 | // 法1:通过 matcher 对象及 while 循环来寻找 |
需要说明的是,对于上面的第2个方法,调用 Matcher 对象的 results()
方法,返回 Stream<MatchResult>
, 其中 MatchResult
为一个接口,它有方法:group()
, start()
, end()
(note1: 实际上,Matcher
类实现了 MatchResult
接口)(Note2: results() 方法是 java 9 新加入的方法,之前的 Matcher
类没有该方法)。
对于上面的方法3,Scanner 对象的 findAll()
方法返回 Stream<MatchResult>
。
group()
: Matcher 类对象的 group()
方法返回匹配到的 括号中的内容 (就是寻找正则表达式中有括号的内容,然后在目标中寻找该内容并返回)。 group(n)
表示返回第 n 个括号所匹配到的内容,(Note: group(0)
返回整个输入。) 此外,我们在 括号中还可以加上标号 例如 (?<currency>[A-Z]{3})
, 然后在寻找时 可以使用 matcher.group("currency");
方法来寻找对应 label中的表达式在目标字符串中的匹配。 (matcher
为 Matcher
类的实例)
c. 其他操作
将 字符串 依据特定的分隔符进行切割,可以使用下述方法:
1 | String input = "1, 2, 3"; // 待处理的字符串 |
根据正则表达式,寻找到特定的字段后进行替换,可以使用如下几种方式:
1 | // 将旁边可能有 空格 的 逗号全部替换为 没有空格的 逗号 |
在进行模式匹配的时候,我们还可以通过添加 flag 的方式,设定匹配的模式,例如:
1 | // 在匹配的时候忽略大小写,并且使用 Unicode 字符集 |
B. 序列化
序列化在计算机科学的数据处理中,是指将数据结构或对象状态转换成可取用格式,以留待后续在相同或另一台计算机环境中,能恢复原先状态的过程。
序列化示例
一个类的对象必须实现了 Serializable
接口才能进行序列化,此外,还要求该类中所有的变量都是基本数据类型或者 已经是可序列化的 类的引用。(Note: Serializable 是一个 marker 接口,只做标记使用,内部没有方法。)
数组和集合类都是可序列化的对象。
下面,通过一组代码展示序列化与反序列化的过程:
1 | // 将对象输出到序列。通过 ObjectOutputStream |
在序列化的过程中,对象的类名以及 所有实例变量的名字和值都会保存,基本数据类型的值被直接存储为 二进制数据,对象会接着调用 writeObject()
进行存储。
此外,在序列化对象时,还会额外保存对象类的版本信息 在 serialVersionUID
中。
需要注意的是,在序列化的时候,每一个对象会获得一个 序列号 (serial number),当进行序列化时,会先判断这个对象的序列号是否之前出现过,如果为重复的对象,则只会在序列化文件中写入序列号而不再重复对该对象进行序列化(保证了同一个对象的唯一性)。
如果不希望对某个实例变量进行序列化(例如存储 cache 内容的类),则使用 transient 修饰符进行修饰。