(这一个章节,将会提及到Java里面很特殊的一个数据类型:String,其类型的主要麻烦在于我们经常会用到它,而且针对它的“不可变”,很多时候很难去理解。附带这个章节会讲到很多关于处理字符串格式的内容,包括使用正则表达式做验证以及使用日期、货币格式化处理,还会提及到的就是如果在使用JDBC的时候针对sql的类型[java.sql包内]和针对Java的类型[java.util]的一些相互转换问题。这一个章节涵盖的内容可能比较小范围,但是我们在开发项目过程中会经常遇到,所以是不得不去了解和不得不去学习的一个章节。方便大家看的时候容易查找代码段,代码部分都有[$]作为段落查找前缀,如果有什么笔误请大家来Email告知:silentbalanceyh@126.com,谢谢!)
- DFA:
DFA引擎在线性时状态下执行,因为它不要求回溯(也就是在匹配过程,它永远不会测试一个相同的字符两次)。DFA引擎还可以确保匹配最长的可能字符串,但是因为DFA引擎只包含了有限的状态,所以它不能匹配具有反向引用的模式;并且因为它不构造显示扩展,所以它不不可以捕获子表达式。 - NFA:
NFA引擎运行使用的“贪婪的”匹配回溯算法,以指定顺序测试正则表达式的所有可能的扩展并接受第一个匹配项。因为传统的NFA构造正则表达式的特定扩展以获得成功的匹配,所以它可以捕获子表达式匹配和匹配的反向引用。但是,因为传统的NFA回溯,所以它可以访问完全相同的状态多次(如果通过不同的路径到达该状态)。因此,在最坏的情况下,它的执行速度可能非常缓慢,因为传统的NFA接受它找到的第一个匹配,所以它可能还会导致其他匹配未被发现。 - POSIX NFA
POSIX NFA引擎与传统的NFA引擎类似,不同的一点在于:在它们可以确保已经找到了可能的最长的匹配之前,它们将继续回溯。因此POSIX NFA引擎的速度比NFA引擎更加慢,并且在使用该引擎的时候,恐怕我们都不愿意在更改回溯搜索的顺序的情况下来支持较短的匹配搜索,而非较长的匹配搜索。
回溯就像在道路的每个分岔口留下一小堆面包屑。如果走了死路,就可以原路返回,直到遇到面包屑标示的尚未尝试过的道路。如果还是死路,继续返回,找到下一堆面包屑,如些重复,直到找到出路,或者走完所有没有尝试过的道路。
不论选择那一种途经,如果它能成功匹配,而且余下的正则也匹配成功了,匹配即告完成。如果余下的正则匹配失败,引擎会回溯到之前做选择时记录的备用途经。这样引擎最终会尝试表达式的所有可能途经(如果没有匹配成功的话)。
回溯的两个要点
如果需要在“进行尝试”和“跳过尝试”之间选择,对于匹配优先量词,引擎会优先选择“进行尝试”,而对于忽略优先量词,会选择“跳过尝试”。
在需要回溯时,距离当前最近储存的选项就是当本地失败强制回溯时返回的。使用的原则是LIFO(last in first out,后进先出)。
表达式 | 可匹配的字符以及含义 |
/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范围时的字符缝隙 |
表达式 | 其含义 |
{n} | 表达式重复n次,比如:a{5}等价于aaaaa |
{m,n} | 表达式至少重复m次,最多重复n次 |
{m,} | 表达式至少要出现m次 |
? | 匹配表达式0次或者1次,等价于{0,1} |
+ | 表达式至少出现1次,等价于{1,} |
* | 表达式不出现或者出现任意次数,等价于{0,} |
符号 | 作用 |
^ | 与字符串开始的地方匹配,不匹配任何字符 |
$ | 与字符串结束的地方匹配,不匹配任何字符 |
. | 条件限制除开/n以外的任意一个单独字符 |
| | 左右两边的表达式之间“或”关系,匹配左边或者右边都可以 |
() | 1.在被修饰匹配的次数的时候,括号中的表达式可以作为整体被修饰 2.取匹配结果的时候,括号中的表达式匹配到的内容可以被单独得到 |
[] | 用来自定义能够匹配多字符的表达式 |
{} | 修饰匹配次数的符号 |
正则表达式写法 | 含义描述 |
^/d+$ |
非负整数(正整数+0) |
^[0-9]*[1-9][0-9]*$ |
正整数 |
^((-/d+)|(0+))$ | 非正整数(负整数+0) |
^-[0-9]*[1-9][0-9]*$ | 负整数 |
^-?/d+$ | 整数 |
^/d+(/./d+)?$ | 非负浮点数(正浮点数+0) |
^(([0-9]+/.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*/.[0-9]+)|([0-9]*[1-9][0-9]*))$ | 正浮点数 |
^((-/d+(/./d+)?)|(0+(/.0+)?))$ | 非正浮点数(负浮点数+0) |
^(-?/d+)(/./d+)?$ | 浮点数 |
^[A-Za-z]+$ | 由26格英文字母组成的字符串 |
^[A-Z]+$ | 由26格大写字母组成的字符串 |
^[A-Za-z0-9]+$ | 由数字和26个英文字母组成的字符串 |
^/w+$ | 由数字、26格英文字母或者下滑线组成的字符串 |
^[/w-]+(/.[/w-]+)*@[/w-]+(/.[/w-]+)+$ | Email地址的验证格式 |
^[a-zA-z]+://(/w+(-/w+)*)(/.(/w+(-/w+)*))*(/?/S*)?$ | URL地址的格式 |
^(d{2}|d{4})-((0([1-9]{1}))|(1[1|2]))-(([0-2]([1-9]{1}))|(3[0|1]))$ | 年-月-日 |
^((0([1-9]{1}))|(1[1|2]))/(([0-2]([1-9]{1}))|(3[0|1]))/(d{2}|d{4})$ | 月/日/年 |
(d+-)?(d{4}-?d{7}|d{3}-?d{8}|^d{7,8})(-d+)? | 手机号码 |
^(d{1,2}|1dd|2[0-4]d|25[0-5]).(d{1,2}|1dd|2[0-4]d|25[0-5])$ | IP地址 |
[/u4e00-/u9fa5] |
中文字符的正则表达式 |
[^/x00-/xff] |
双字节 |
^[1-9]*[1-9][0-9]*$ |
腾讯QQ号 |
^d{15}|d{}18$ |
国内身份证格式【没有验证生日】 |
(/(/d{3,4}/)|/d{3,4}-|/s)?/d{8} |
国内的电话号码 |
- 首先是Matcher的find方法,find方法做了两个事情,首先是指代目标字符串是否能够匹配我们所给的字符串,所以它的返回值是boolean,另外就是将匹配的游标指向下一个匹配的位置,这一点一定要记得
- Matcher的group方法主要是提取出来目标字符串里面匹配的字符串的文字,从上边的输出就可以知道只有能够匹配的位置然后group返回的就是两个$符号中间的内容
- appendReplacement方法:
此方法将执行下边的操作:
[1]它从添加位置开始在输入序列读取字符,并且将其添加到给定的字符串缓冲区,在读取以前匹配之前的最后字符(索引位于start() - 1处)之后,它就会停止
[2]它将给定替换字符串添加到字符串缓冲区
[3]它将此匹配器的添加位置设置为最后匹配位置的索引加1,即end() - appendTail方法:
这个方法应该执行下边的操作:此方法从添加位置开始从输入序列读取字符,并将其添加到给定字符串缓冲区,可以在一次或多次调用appendReplacement方法后调用它来复制剩余的输入序列
- 强类型语言:强类型语言有强制数据类型的定义,也就是说,一旦一个变量被指定了某个数据类型,如果不经过强制类型转换,那么它永远就是这个数据类型了。举个例子:如果你定义一个整型变量a,那么程序根本不可能将a当作字符串类型处理,换一个角度来讲,强类型语言是类型安全的语言。Java就是一个典型的强类型定义的语言,因为它存在严格的类型定义,比如String、int、short、long等各种类型。
- 弱类型语言:弱类型语言是指类型可以被忽略的语言,它与强类型定义的语言想法,一个变量可以赋不同数据类型的值。比如我们常用的PHP和JavaScript是典型的弱类型,这里需要区分的一点是:弱类型语言不是说变量完全没有类型,是说类型的定义不如强类型语言一样很严格,比如下边的PHP代码:
$a= 1;
$a="Hello";
这种情况如果出现在Java里面就会因为类型问题报错,因为在强类型语言里面数据转换是有特殊规则的,上边代码也只有像JavaScript和PHP这种若类型语言可以完全通过编译
- 动态类型语言:动态类型语言是指在运行期间才会去做数据类型检查的语言,也就是说,在用动态类型的语言编程的时候,永远也不用给任何变量指定数据类型,该语言会在我们编程的第一次给变量赋值的时候进行内部的数据类型的记录。
- 静态类型语言:静态类型语言与动态类型语言相反,它的数据类型是在编译期间检查的,也就是说在写程序的时候需要声明所有的数据类型,而Java就是其中代表之一
- 有些方法目前已经被JDK放弃了,最原始的字符串到时间的转化为:
Date date = Date.parse(inputValue);
上边这种格式会报编译错误,而且Date.parse方法是被弃用的一个方法,替代方法为:DateFormat.parse(String s)现在很多时候开发项目并不使用这种方法进行String到Date的操作
关于Date的parse静态方法的说明如下:
尝试把字符串s解释为日期和时间的表示形式,如果尝试成功,则返回指示的时间,用该时间与历元(1970年1月1日,00:00:00 GMT)的时间差来表示(以毫秒为单位),如果尝试失败就会抛出IllegalArgumentException异常。这个方法接受很多语法,特别是它识别IETF标准日期语法:“Sat,12 Aug 1995 13:30:00 GMT”,它也了解美国大陆市区缩写,但对于一般用途,应该使用时区偏移量:(比格林威治子午线晚 4 小时 30 分)。如果没有指定时区,则假定用本地时区,GMT和UTC被认为是相同的。系统将从左到右处理字符串inputValue,从中查找相对应的数据,inputValue中包含在ASCII括号字符中的任何内容都被忽略,inputValue只允许下边这些字符集:
abcdefghijklmnopqrstuvwxyz
ABCDEFGHIJKLMnopQRSTUVWXYZ
0123456789,+-:/
以及空白 - 还有一点需要说明的是(下边是api文档里面的内容):
连续的十进制位序列被当成十进制数:
[1]如果数字前面有 + 或 -,并且已经识别了年份,那么数字就是一个时区偏移量。如果数字少于 24,那么它是以小时进行测量的偏移量。否则,它被认为是以分钟进行测量的偏移量,用没有标点的 24 小时时间格式来表示。前面的 - 意味着向西的偏移量。时区偏移量始终相对于 UTC(格林威治)。因此,例如,在字符串中出现的 -5 意味着“比格林威治时间晚 5 小时”,+0430 将意味着“比格林威治时间早 4 小时 30 分”。允许字符串冗余地指定 GMT、UT 或 UTC——例如,GMT-5 或 utc+0430。
[2]如果下面条件之一为真,数字就被认为是年数:
——数字等于或大于 70,并且后跟一个空格、逗号、斜杠或结束字符串
——数字小于 70,并且已经识别月份和月中的某一天
如果被识别的年数小于 100,它就被解释为相对于其日期所在世纪的缩写年,缩写年的日期位于初始化 Date 类的时间的 80 年以前和 19 年以后之间。在调整年数后,从其减去 1900。例如,如果当前的年份是 1999,那么范围 19 至 99 的年数就被假定表示 1919 至 1999,而 0 至 18 的年数就被假定表示 2000 至 2018。注意,这与 SimpleDateFormat 中使用的小于 100 的年份具有稍微不同的解释。
[3]如果数字后跟一个冒号,则认为是小时,如果小时已经被识别,则认为是分钟。
[4]如果数字后跟一个斜杠,则认为是月份(把它减 1,以便产生范围 0 至 11 的数字),如果月份已经被识别,则认为它是月中的某一天。
[5]如果数字后跟空白、逗号、连字符或结束字符串,那么如果小时已识别但分钟未识别,则认为是分钟;否则,如果分钟已识别,而秒没有识别,则认为是秒;否则,它被认为是月中的某一天。
连续的字母序列被认为是单词,并按以下方法进行处理:
[1]忽略匹配 AM(忽略大小写)的单词(但如果小时尚未识别,或者小时小于 1 或大于 12,则解析失败)。
[2]匹配 PM(忽略大小写)的单词,添加 12 到小时(但如果小时尚未识别,或者小时小于 1 或大于 12,则解析失败)。
[3]忽略匹配 SUNDAY、MONDAY、TUESDAY、WednESDAY、THURSDAY、FRIDAY 或 SATURDAY 的任何前缀(忽略大小写)的任何单词。例如,sat、Friday、TUE 和 Thurs 会被忽略。
[4]否则,匹配 JANUARY、FEBRUARY、marcH、APRIL、MAY、JUNE、JULY、AUGUST、SEPTEMBER、OCTOBER、NOVEMBER 或 DECEMBER 的任何前缀(忽略大小写,并按这里给出的顺序考虑它们)的任何单词都被识别为指定月份,并被转换成一个数字(0 至 11)。例如,aug、Sept、april 和 NOV 被识别为月份。Ma 也是这样,它被识别为 marcH,而不是 MAY。
[5]匹配 GMT、UT 或 UTC(忽略大小写)的任何单词都认为是指 UTC。
[6]匹配 EST、CST、MST 或 PST(忽略大小写)的任何单词都被认为是指北美的时区,该时区分别比格林威治时间晚 5、6、7 或 8 小时。匹配 EDT、CDT、MDT 或 PDT(忽略大小写)的任何单词都被识别为在夏令时期间分别指相同的时区。
一旦扫描了整个字符串,就以两种方式之一把它转换成时间结果。如果已经识别时区或时区偏移量,那么年、月、月中某一天、小时、分钟和秒以 UTC 进行解释,然后应用时区偏移量。否则,年、月、月中某一天、小时、分钟和秒用本地时区进行解释。
- 前边已经说明Java的基础类型有八种,在八种基础类型转化为String的时候,只能使用String的静态方法String.valueOf(),而不能使用toString()方法,因为基础类型不支持toString()方法,但是包装过的类型不一样,使用基础类型的包装类型的时候是可以使用toString()方法的。
- 关于toString()方法需要简单说明:在Java里面,所有的对象都有toString()方法,这个方法继承于Object类,一般情况下在没有重写的情况下,格式为:
java.lang.Object@de6ced
@前边部分是该引用的类型,后边是对象的一种标识,在没有重写toString方法的时候,其格式针对每个对象都是固定的 - 还有一点需要说明的是:Integer这种类似包装类的类型的toString方法是经过重写过的,比如上边的代码:
System.out.println(b.toString());
如果改写成:
System.out.println(b);
其输出结果不会变化 - 在针对所有的类型这里都是一样的,比如其他的原始类型比如boolean、short或者其他的包装类型Float或者Double等等,也就是说:上边这段代码是从基本类型到String的概念说明代码,所有的基本类型以及包装类型都可以通过这种方式来转换。反过来转换的办法就不做说明,一般为:Integer.parseInt的格式,这种方式可以使得String转换称为一个int,这种方法的衍生可以去查询API
- 关于JSON和XML的数据格式这里不做说明,这个会在序列化中讲到
- 关于二进制数据比如图片读取这里也不做说明,这个会保留到IO章节中
- java.util.Date
- java.text.DateFormat(抽象类)和它的子类java.text.SimpleDateFormat(具体类)
- java.util.Calendar(抽象类)和它的子类java.util.GregorianCalendar(具体类)
字段 | 默认值 | |
ERA | AD | |
YEAR | 1970 | |
MONTH | JANUARY | |
DAY_OF_MONTH | 1 | |
DAY_OF_WEEK | 一个星期的第一天 | |
WEEK_OF_MONTH | 0 | |
DAY_OF_WEEK_IN_MONTH | AM_PM | AM |
HOUR,HOUR_OF_DAY,MINUTE, SECOND,MILLISECOND |
0 |
字母 | 日期或时间元素 | 示例子 | ||
G | Gra标志符 | AD | ||
y | 年 | 1996;96 | ||
M | 年中的月份 | July;Jul;07 | ||
w | 年中的周数 | 27 | ||
W | 月份中的周数 | 2 | ||
D | 年中的天数 | 189 | ||
d | 月份中的天数 | 10 | ||
F | 月份中的星期 | E | 星期中的天数 | Tuesday;Tue |
a | Am/pm标记 | PM | ||
H | 一天中的小时数(0-23) | 0 | ||
k | 一天中的小时数(1-24) | 24 | ||
K | am/pm中的小时数(0-11) | h | am/pm中的小时数(1-12) | 12 |
m | 小时中的分钟数 | 30 | ||
s | 分钟中的秒数 | 55 | ||
S | 毫秒数 | 978 | ||
z | 时区 | Pacific Standard Time; PST;GMT-08:00 |
||
Z | -0800 |
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。