Java里面很特殊的一个数据类型:String,其类型的主要麻烦在于我们经常会用到它,而且针对它的“不可变”,很多时候很难去理解。附带这个章节会讲到很多关于处理字符串格式的内容,包括使用正则表达式做验证以及使用日期、货币格式化处理,还会提及到的就是如果在使用JDBC的时候针对SQL的类型[java.sql包内]和针对Java的类型[java.util]的一些相互转换问题。这一个章节涵盖的内容可能比较小范围,但是我们在开发项目过程中会经常遇到,所以是不得不去了解和不得不去学习的一个章节。方便大家看的时候容易查代码段,代码部分都有[$]作为段落查前缀,如果有什么笔误请大家来Email告知:silentbalanceyh@126,谢谢!)
本章目录
1.不可变类
2.String详解
3.StringBuilder和StringBuffer详解
4.正则表达式
5.关于转型
6.货币、时间、日期格式化
4.正则表达式
i.简介:
在程序开发过程,很多时候需要针对文本进行处理,这里撇开文件的IO先不提,在处理过程中往往会遇到匹配、查、替换、判断字符串的情况发生,而这些情况有些时候往往变得异常复杂。在文本处理里面,常用的手段就是正则表达式,对于新手可能不明白正则表达式是干什么的,这里先简单介绍一下:
正则表达式是一种用来进行模式匹配和替换的规范,一个正则表达式本身就是由普通的字符组成的文字模式,它的主要目的就是以正则表达式为模板,将需要分析的文本以及提供的搜索字符串进行匹配。Java自1.4开始有了包,该包为我们提供了一个很好的Java正则表达式的应用。学习最初先看一个比较简单的进行判断的正则表达式的例子:
package org.;
import Matcher;
import Pattern;
/**
*正则表达式初次接触
**/
public class RegexFirst{
public static void main(String args[]){
String inputValue=new String("abcaaaabcaaaaabcccc");
Pattern pattern=Patternpile("abc");
Matcher matcher=pattern.matcher(inputValue);
int number=0;
while(matcher.find()){
number++;
}
System.out.println("Patterns:"+number);
}
}
上边这段代码不列出输出,需要注意的是Pattern的参数,上边这段代码做了些什么事情呢?上边的目标字符串为inputValue的值,而Pattern定义了一个简单的模式,也就是上边的代码就做了一件事情:查abc字符串在输入字符串中出现的次数。运行上边的代码就可以看到匹配次数是三次,也就是abc字符串在输入字符串里面出现了三次。
ii.正则引擎[参考合作者网站:www.xwooo/]
1)简介:
使用正则表达式(Regular Expression)处理文本是一个不错的选择,因为它本身就是一个便捷、高效的文本处理工具,它能够针对目标文本进行添加、删除、分离、叠加、插入以及修正各种类别的文本和数据,一旦掌握了过后就可以很方便针对文本里面的所需数据进行各种提取操作,各种语言都提供了一定的处理正则表达式的库。一般来说,正则表达式引擎分为两大类:
一种是DFA、一种是NFA——这两种引擎有很久的历史了,当中也由这两种引擎产生了很多变体!于是就有了POSIX出台,它的出现使得正则表达式变得更加规范化了,这样的改变使得正则表达式引擎分成了三种类型:DFA、NFA(相对传统)、POSIX NFA ∙DFA:
DFA引擎在线性时状态下执行,因为它不要求回溯(也就是在匹配过程,它永远不会测试一个相同的字符两次)。DFA引擎还可以确保匹配最长的可能字符串,但是因为DFA引擎只包含了有限的状态,所以它不能匹配具有反向引用的模式;并且因为它不构造显示扩展,所以它不不可以捕获子表达式。
∙NFA:
NFA引擎运行使用的“贪婪的”匹配回溯算法,以指定顺序测试正则表达式的所有可能的扩展并接受第一个匹配项。因为传统的NFA构造正则表达式的特定扩展以获得成功的匹配,所以它可以捕获子表达式匹配和匹配的反向引用。但是,因为传统的NFA回溯,所以它可以访问完全相同的状态多次(如果通过不同的路径到达该状态)。因此,在最坏的情况下,它的执行速度可能非常缓慢,因为传统的NFA接受它到的第一个匹配,所以它可能还会导致其他匹配未被发现。
∙POSIX NFA
POSIX NFA引擎与传统的NFA引擎类似,不同的一点在于:在它们可以确保已经到了可能的最长的匹配之前,它们将继续回溯。因此POSIX NFA引擎的速度比
NFA引擎更加慢,并且在使用该引擎的时候,恐怕我们都不愿意在更改回溯搜索的顺序的情况下来支持较短的匹配搜索,而非较长的匹配搜索。
2)分类:
目前使用的引擎主要有:
DFA引擎:awk、egrep、flex、lex、MySQL、Procmail等
NFA引擎:GNU Emacs、Java、ergp、less、more、.NET、PCRE library、Perl、PHP、Python、Ruby、Sed、Vi
POSIX NFA引擎:mawk、Mortice Kern Systems'utilities、GNU Emacs
DFA/NFA混合的引擎:GNU awk、GNU grep/egrep、Tcl
举个简单的例子:
比如有字符串this is yansen's blog,正则表达式为/ya(msen|nsen|nsem)/【这里只是为了区别NFA和DFA,至于正则表达式的写法不是java语言里面使用的写法,前边这样的写法我平时开发在javascript写客户端脚本的时候蛮常用的】
NFA工作方式如下:
现在字符串查y然后匹配其后是否为a,如果是a就继续,查其后是否为m如果不是则匹配其后是否为n(这个时候淘汰掉msen),然后继续看其后是否一次为s、e,接着测试是否为n,是n则匹配成功,不是则测试是否为m。为什么这里是m呢?因为NFA工作方式是以正则表达式为标准,反复测试字符串,这样同一个字符串有可能被反复测试了很多次!
DFA工作方式如下:
DFA会从this中t开始一次查y,定位到y,已知其后为a,则查看是否表达式中有a,此处正好有a,然后字符串a后为n,DFA依次测试表达式,此时msen不符合要求淘汰。nsen和nsem符合要求,然后DFA依次检查字符串,检测到sen中的n时只有nsen分支符合,则匹配成功。
从上边这个简单的例子可以知道:两种引擎的工作方式截然不同,一个NFA以表达式为主导,一个DFA以文本为主导!一般来说,DFA引擎则搜索更快一些!但是NFA以表达式为主,反而更容易操纵,因此一般程序员更偏爱NFA引擎!
3)构成:
既然是一个表达式引擎一定会有多种零件,要真正了解引擎的工作原理,就必须先了解其零件,正则
引擎的零件主要有以下几个:
文字字符:
一般如:a、\*、!、好
如果一个正则表达式只包含纯文本字符,如上边的abc,则正则引擎会视为:a后边接着一个b,然后接着一个c,这种格式很容易理解。
字符组[…]、点号.、Unicode属性以及其他:
需要说明的一点就是无论字符组的长度多长,它都只能匹配一个字符
捕获型括号():
用于捕获文本的括号,不会影响到匹配过程
锚点:
锚点可以分为:简单锚点和复杂锚点
简单锚点只是检查目标字符中的特性位置(如^,$),或者是比较两个相邻的字符(\<,\b)复杂锚点(环视)能包含任意复杂的子表达式
非“电动”的括号、反向引用和忽略优先量词
捕获括号、以用相应的反向引用和表示法(如$1或\1)、忽略优先量词只对NFA引擎起作用,DFA不支持。
4)关于回溯:
这里提及到回溯主要是因为它是NFA引擎中很重要的一点:
NFA引擎最重要的性质就是,它会依次处理各个表达式或组合元素,遇到需要在两个可能成功的途经中进行选择的时候,它会选择其一,然后记住另一个选项,以备稍后可能的需要。一般需要做出选择的情形包括量词和多选结构。
真实世界中的面包屑
回溯就像在道路的每个分岔口留下一小堆面包屑。如果走了死路,就可以原路返回,直到遇到面包屑标示的尚未尝试过的道路。如果还是死路,继续返回,到下一堆面包屑,如些重复,直到到出路,或者走完所有没有尝试过的道路。
时间正则表达式java
不论选择那一种途经,如果它能成功匹配,而且余下的正则也匹配成功了,匹配即告完成。如果余下的正则匹配失败,引擎会回溯到之前做选择时记录的备用途经。这样引擎最终会尝试表达式的所有可能途经(如果没有匹配成功的话)。
回溯的两个要点
如果需要在“进行尝试”和“跳过尝试”之间选择,对于匹配优先量词,引擎会优先选择“进行尝试”,而对于忽略优先量词,会选择“跳过尝试”。
在需要回溯时,距离当前最近储存的选项就是当本地失败强制回溯时返回的。使用的原则是LIFO(last in first out,后进先出)。
iii.正则表达式语法:
由上边演示的代码可以知道,真正起作用的是这句话:
Pattern pattern=Patternpile("abc");
这里传入的abc对Java初学者而言就是一个字符串,实际这个字符串有特殊的意义,因为它代表的是正则表达式,而不是一个字符串,上边的表达式已经在前边章节解释过含义了,那么正则表达式的其他写法应该如何进行呢:
1)正则表达式基本用法:
[1]普通字符:
正则表达式的构成为:字母、数字、汉字、下划线、以及没有特殊定义的标点符号都属于正则表达式里面的普通字符,表达式中的普通字符在匹配一个字符串的时候,匹配与之相同的一个字符就可以。上边提供的例子说明的就是这类字符。
[2]多字符表达式:
因为在书写过程会出现一些特殊字符,有些需要进行转义,使用"\"的方法区分,转义字符对很多学习过编程的人应该不难理解,因为这些字符都带有很特殊的含义:这里主要列举常用的一些多字符表达式:
表达式可匹配的字符以及含义
\s 匹配所有空白字符、制表符、换页符中任意一个,等价自定义表达式:
[\t\n\x0B\f\r]
\w任意一个字母或数字以及下划线,等价表达式:
[a-zA-Z_0-9]
\d任意一个数字,0到9中的任意一个,等价表达式:
[0-9]
\b标识一个单词的边界
\S匹配所有的非空白符号,等价表达式:
[^\t\n\x0B\f\r]
\W匹配所有的字母、数字、下划线以外的字符,等价表达式:
[^a-zA-Z_0-9]
\D匹配任意一个非数字,等价表达式:
[^0-9]
\B匹配一个非单词的边界,即左右两边都是\w范围或者左右两边都
不是\w范围时的字符缝隙
[3]修饰规则
上边部分谈到的都是表达式匹配一个字符的规则,任何时候都只能匹配一次,而有一种办法还可以修饰模式里面字符的数目,比如:
[b][b][b]可以写成[b]{3}
其写法为:“次数修饰符”直接放在“被修饰的表达式”后边,就像上边这样的写法就是这样的一个简单的例子
其修饰表为:
表达式其含义
{n}表达式重复n次,比如:a{5}等价于aaaaa
{m,n}表达式至少重复m次,最多重复n次
{m,}表达式至少要出现m次
?匹配表达式0次或者1次,等价于{0,1}
+表达式至少出现1次,等价于{1,}
*表达式不出现或者出现任意次数,等价于{0,}
[4]特殊符号:
正则表达式里面还有一些比较特殊的匹配符号,如上边需要转义的^、$、.等都是正则表达式中很特殊的符号,这些符号具有特殊的含义:
符号作用
^与字符串开始的地方匹配,不匹配任何字符
$与字符串结束的地方匹配,不匹配任何字符
.条件限制除开\n以外的任意一个单独字符
|左右两边的表达式之间“或”关系,匹配左边或者右边都可以
()1.在被修饰匹配的次数的时候,括号中的表达式可以作为整体被修饰
2.取匹配结果的时候,括号中的表达式匹配到的内容可以被单独得到
[]用来自定义能够匹配多字符的表达式
{}修饰匹配次数的符号
所以上边的[3]和[4]这些出现的符号如果需要进行录入的时候都需要使用转义,比如?应该使用\?、等价的|符号应该使用\|,其他符号可以参见上边的表
[5]Pattern类里面的字段摘要:
static int CANON_EQ:[Pattern.CANON_EQ]
当且仅当两个字符的"正规分解(canonical decomposition)"都完全相同的情况下,才认定匹配。比如用了这个标志之后,表达式"a\u030A"会匹配"?"。默认情况下,不考虑"规范相等性(canonical equivalence)"
static int CASE_INSENSITIVE(?i):[Pattern.CASE_INSENSITIVE]
默认情况下,大小写不明感的匹配只适用于US-ASCII字符集。这个标志能让表达式忽略大小写进行匹配。要想对Unicode字符进行大小不明感的匹配,只要将UNICODE_CASE 与这个标志合起来就行了
static int COMMENTS(?x):[Pattern.COMMENTS]
在这种模式下,匹配时会忽略(正则表达式里的)空格字符(译者注:不是指表达式里的"\\s",而是指表达式里的空格,tab,回车之类)。注释从#开始,一直到这行结束。可以通过嵌入式的标志来启用Unix行模式

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。