Previously on OOP:
To divide a String into several fields, we can use split() function, regular expression, or a Scanner. Afterwards, it is possible to store the fields into a compound data structure / Java generics.
在本文中,本黄鸭要举几个其他regular expression的例子。如果想要正常使用regular expression,必须在.java文件的开头import一组“regex”系列的头文件:
Example 1
Pattern类中存放的是用符号语言写的字符串格式。在本段代码中,字符串的格式是:第一位是正号、负号,或者没有,即问号表示optional;第二位是一个非零的数字;后面可以有若干位数字,也可以没有,即星号表示的是repetition 0 or more;竖线和零表示alternatively 0。
Pattern类的matcher函数的参数是需要和Pattern比对的字符串。在前一篇文章中,我们把从文件中读取到的一行作为这里的字符串。而在本段代码中,字符串只含有一个字符:“0”。
再调用Matcher类的matches()函数,判断整个字符串和Pattern是否匹配。如果匹配的话,显示“Matched!”字符串;反之,显示“NOT Matched!”字符串。那么,运行的结构是匹配还是不匹配呢?答案是匹配的。
Example 2
本段代码中的regular expression旨在检验字符串是否是float类型的。如果是,那么就使用capture groups来打印sign, integer part, and decimal part。
Matcher类的group()函数可以用编号来指明capture groups。首先,编号是的capture group是整个进行比对的字符串。其他capture groups都是按照Pattern中的括号划分的。在本段代码中,从左到右有三组括号:“([+-]?)”,“([1-9][0-9]*|0)”,“([0-9]+)”,分别是capture group 1,2,3。
如果括号不是从左到右的,而是有层次的、括号里面有括号的,那么capture groups应该如何编号呢?这是一个深刻的问题,本黄鸭会在下面的例子中提到。
还有一个重点是转义字符。小数点“.”,就是一种需要转义的字符。之所以需要转义,是因为小数点对于编译器来说有其他的意义,写在字符串里面不会当做字符串的一个部分来理解,而会触发其他的剧情。转义的做法是在前面加上反斜线“\”,这种斜线的英语叫做back slash。但是不幸的是,back slash也是一种需要转义的字符,所以前面一共有两个反斜线符号。
最后,“([0-9]+)”中的加号表示repetition 1 or more,它和星号是有差别的,因为至少要有一个0-9之内的数字。
Matcher类的find()函数可以找到字符串中第一个、局部最长的、满足Pattern的子字符串。本段代码中的字符串不仅包含float类型的数据,还有其他字符,如果调用matches()函数,返回值肯定是false,即不匹配。而使用find()字符能把float number从其他字符中分离出来。
Example 3
A CSV is organized in lines,each line contains a sequence of values separated by ",". And fieldscan beany type(e.g. strings, integers, floats, etc.)由CSV文件的结构可以看出,用regular expression来parsing a CSV file是很普遍的。
最常见的做法是:先按行读取CSV文件,把字符串按照分隔符逗号拆开成字段,然后存放在类似于People这样的类中,最后再存放到Java Generic的数据结构中。
本段代码中的字符串由三个字段构成,之间用逗号隔开,可以看做是一个CSV文件中的一行。定义的Pattern中的“[^,]”表示matches any single character not“,”。那么,csvMatcher.find()找到的第一个子字符串是“John”。第二个子字符串会在去掉“John”以后、剩下的字符串中继续找,所以找到的是“Smith”,最后一个是“1234”。想要依次找到所有的字段,用while循环结构就可以做到。
Example 4
本段代码中的字符串和CSV文件有些不同,有两个用逗号分隔的字段又被引号括在了一起。所以,在读取的时候,要求把引号括在一起的视为一个字段,其他字段仍然按照逗号划分。
本黄鸭的想法是先把引号全删了,全部按照逗号划分,然后在分字段存放的类中,把引号括起来的组合在一起。显然,这种做法不如直接用regular expression方便。
但前提是regular expression的Pattern必须要编写出来。如果第一位是引号,那么读到下一个引号之间都是同一个字段,也就是两个引号之间不能包含是引号的字符:"([^"]*)"。或者是不是逗号的字符:([^,"]+)。两者之间用“|”连接,表示“或”。另外,引号也是一种需要转义的字符,前面必须有反斜线。
本段代码的while循环结构中的if条件句是有用的,不是写着玩的。当group(1)中没有值时,也就是字段的内容没有放在引号中,那么我们应该看看group(2),即字段有没有用逗号分隔开。
Example 5
Albert出场自带双引号。要求还是把单引号括在一起的视为一个字段,其他字段仍然按照逗号划分。也就是说,读到下一个单引号之间都是同一个字段,即两个引号之间既不能包含单引号,也不能包含双引号:"(([^"]+|"")*)"。
此外,本段代码的Pattern就是有层次的、括号里面有括号的,我们刚好来研究一个capture groups是按照什么编号的:
第零个还是整个Pattern,第一个是(([^"]+|"")*),第二个是([^"]+|""),第三个是([^,"]+)。所以,当content没有取到的时候,也就是字段不在两个单引号之间,我们应该去看group(3),而不是group(2)。
Example 6
如果一个字符段是空,会连着写两个逗号,用英语说是:two consecutive separators。在这种情况下,我们的Pattern应该和本段代码中的编写得一样。看到这个Pattern,本黄鸭已经醉了,小于号和等于号are beyond cognitive ability,基本看不懂。万一各位宝宝们遇到了这样的CSV文件,知道有这么一个例子就行了。
欢迎使用本黄鸭编写的小程序~
微信公众号二维码:
领取专属 10元无门槛券
私享最新 技术干货