第十八章 字符串

+的重载与StringBuilder

用于String++=是Java中仅有的两个重载过的操作符,Java不允许程序员重载任何其他的操作符。编译器自动引入了java.lang.StringBuilder类进行了优化。

StringBuilder是Java SE5引入的,在这之前用的是StringBuffer。后者是线程安全的,因此开销也会大些。使用StringBuilder进行字符串操作更快一点。

可以用JDK自带的javap工具来反编译:

javap -c Concatenation.class

格式化输出

printf()

Java SE5推出了C语言中 printf() 风格的格式化输出这一功能。

System.out.format()

format()方法模仿了C语言的printf()format()printf()是等价的。

Formatter类

在Java中,所有的格式化功能都是由java.util.Formatter类处理的。可以将Formatter看做一个翻译器,它将你的格式化字符串与数据翻译成需要的结果。

Formatter的重载构造器支持输出到多个路径,不过最常用的还是PrintStreamOutputStreamFile

格式化修饰符

语法:

%[argument_index$][flags][width][.precision]conversion

最常见的应用是控制一个字段的最小长度,这可以通过指定width来实现。

width相对的是precision,用于指定最大长度。width可以应用于各种类型的数据转换,并且其行为方式都一样。precision则不然,不是所有的类型都能使用precision,而且,应用于不同类型的数据转换时,precision的意义也不同。在将precision应用于String时,它表示打印string时输出字符的最大数量。而在将precision应用于浮点数时,它表示小数部分要显示出来的位数(默认是6位小数),如果小数位数过多则舍入,太少则在尾部补零。由于整数没有小数部分,所以precision无法应用于整数,如果你对整数应用precision,则会触发异常。

Formatter转换

类型 含义
d 整型(十进制)
c Unicode字符
b Boolean值
s String
f 浮点数(十进制)
e 浮点数(科学计数)
x 整型(十六进制)
h 散列码(十六进制)
% 字面值“%”

String.format()

String.format()是一个static方法,它接受与Formatter.format()方法一样的参数,但返回一个String对象。当你只需使用一次format()方法的时候,String.format()用起来很方便。

String string = String.format("(t%d, q%d) %s", transactionID, queryID, message);

正则表达式

正则表达式是一种强大而灵活的文本处理工具。

基础

在其他语言中,\\表示“我想要在正则表达式中插入一个普通的(字面上的)反斜线,请不要给它任何特殊的意义”。而在Java中,\\的意思是“我要插入一个正则表达式的反斜线,所以其后的字符具有特殊的意义。”例如,如果你想表示一位数字,那么正则表达式因该是\\d。如果你想插入一个普通的反斜线,应该这样写\\\。不过换行符和制表符之类的东西只需要使用单反斜线:\n \t

在正则表达式中,用括号将表达式进行分组,用竖线|表示或操作。

\\W,它的意思是一个非单词字符(如果W小写,\\w,则表示一个单词字符)。

应用正则表达式最简单的途径,就是利用String类内建的功能:

boolean matches = "-1234".matches("-?\\d+");
String[] split = knights.split(regex);
String replaceFirst = s.replaceFirst("f\\w+", "located");
String replaceAll = s.replaceAll("shrubbery|tree|herring", "banana");

创建正则表达式

正则表达式的完整构造子列表,请参考JDK文档java.util.regex包中的Pattern类。

表达式 含义
B 指定字符B
\xhh 十六进制值为0xhh的字符
\uhhhh 十六进制表现为0xhhhh的Unicode字符
\t 制表符Tab
\n 换行符
\r 回车
\f 换页
\e 转义(Escape)

以下是一些创建字符类的典型方式,以及一些预定义的类:

表达式 含义
. 任意字符
[abc] 包含a、b或c的任何字符
[^abc] 除a、b和c之外的任何字符(否定)
[a-zA-Z] 从a到z或从A到Z的任何字符(范围)
[abc[hij]] a、b、c、h、i、j中的任意字符
[a-z&&[hij]] 任意h、i或j(交)
\s 空白符(空格、tab、换行、换页、回车)
\S 非空白符([^\s])
\d 数字([0-9])
\D 非数字([^0-9])
\w 词字符([a-zA-Z_0-9])
\W 非词字符([^\w])
逻辑操作符 含义
XY Y跟在X后面
X Y
(X) 捕获组(capturing group)。可以在表达式中用\i引用第i个捕获组
边界匹配符 含义
^ 一行的开始
$ 一行的结束
\b 词的边界
\B 非词的边界
\G 前一个匹配的结束

目的并不是编写最难理解的正则表达式,而是尽量编写能够完成任务的、最简单以及最必要的正则表达式。一旦真正开始使用正则表达式了,你就会发现,在编写新的表达式之前,你通常会参考代码中已经用到的正则表达式。

量词

量词描述了一个模式捕获输入文本的方式:

  • 贪婪型: 量词总是贪婪的,除非有其他的选项被设置。贪婪表达式会为所有可能的模式发现尽可能多的匹配。导致此问题的一个典型理由就是假定我们的模式仅能匹配第一个可能的字符组,如果它是贪婪的,那么它就会继续往下匹配。
  • 勉强型: 用问号来指定,这个量词匹配满足模式所需的最少字符数。因此也被称作懒惰的、最少匹配的、非贪婪的或不贪婪的。
  • 占有型: 目前,这种类型的量词只有在Java语言中才可用(在其他语言中不可用),并且也更高级,因此我们大概不会立刻用到它。当正则表达式被应用于String时,它会产生相当多的状态,以便在匹配失败时可以回溯。而“占有的”量词并不保存这些中间状态,因此它们可以防止回溯。它们常常用于防止正则表达式失控,因此可以使正则表达式执行起来更高效。

贪婪型 | 勉强型 | 占有型 | 如何匹配

---|---

X? | X?? | X?+ | 一个或零个X

X* | X? | X+ | 零个或多个X

X+ | X+? | X++ | 一个或多个X

X{n} | X{n}? | X{n}+ | 恰好n次X

X{n,} | X{n,}? | X{n,}+ | 至少n次X

X{n,m} | X{n,m}? | X{n,m}+ | X至少n次,但不超过m次

应该非常清楚地意识到,表达式X通常必须要用圆括号括起来,以便它能够按照我们期望的效果去执行。

在使用正则表达式时很容易混淆,因为它是一种在Java之上的新语言。

CharSequence

接口CharSequenceCharBufferStringStringBufferStringBuilder类中抽象出了字符序列的一般化定义。多数正则表达式操作都接受CharSequence类型参数。

Pattern和Matcher

导入java.util.regex包,然后用static Pattern.compile()方法来编译你的正则表达式。它会根据你的String类型的正则表达式生成一个Pattern对象。接下来,把你想要检索的字符串传入Pattern对象的matcher()方法。matcher()方法会生成一个Matcher对象,它有很多功能可用。

Pattern类还提供了一个static方法:

static boolean matches(String regex, CharSequence input)

编译后的Pattern对象还提供了split()方法,它从匹配了regex的地方分割输入字符串,返回分割后的子字符串String数组。

通过调用Pattern.matcher()方法,并传入一个字符串参数,我们得到了一个Matcher对象。使用Matcher上的方法,我们将能够判断各种不同类型的匹配是否成功:

boolean matches()
boolean lookingAt()
boolean find()
boolean find(int start)

find()

Matcher.find()方法可用来在CharSequence中查找多个匹配。

find()方法像迭代器那样向前遍历输入字符串。重载的find()接收一个整型参数,该整数表示字符串中字符的位置,并以其作为搜索的起点,能够根据其参数的值,不断重新设定搜索的起始位置。

组(Groups)

组是用括号划分的正则表达式,可以根据组的编号来引用某个组。组号为0表示整个表达式,组号1表示被第一对括号括起来的组,以此类推。

Matcher对象提供了一系列方法,用以获取与组相关的信息:

public int groupCount() 返回该匹配器的模式中的分组数目,组0不包括在内。

public String group() 返回前一次匹配操作(例如find())的第0组(整个匹配)。

public String group(int i) 返回前一次匹配操作期间指定的组号,如果匹配成功,但是指定的组没有匹配输入字符串的任何部分,则将返回null

public int start(int group) 返回在前一次匹配操作中寻找到的组的起始索引。

public int end(int group) 返回在前一次匹配操作中寻找到的组的最后一个字符索引加一的值。

start()和end()

注意,find()可以在输入的任意位置定位正则表达式,而lookingAt()matches()只有在正则表达式与输入的最开始处就开始匹配时才会成功。matches()只有在整个输入都匹配正则表达式时才会成功,而lookingAt()只要输入的第一部分匹配就会成功。

Pattern标记

Pattern类的compile()方法还有另一个版本,它接受一个标记参数,以调整匹配行为:

Pattern Pattern.compile(String regex, int flag)

其中的flag来自以下Pattern类中的常量

编译标记 效果
Pattern.CANON_EQ 当且仅当两个字符的完全规范分解相匹配时,才认为它们是匹配的。例如,如果我们指定这个标记,表达式\u003F就会匹配字符串?。默认情况下,匹配不考虑规范的等价性
Pattern.CASE_INSENSITIVE(?i) 默认情况下,大小写不敏感的匹配假定只有US-ASCII字符集中的字符才能进行。这个标记允许模式匹配不考虑大小写(大写或小写)。通过指定UNICODE_CASE标记及结合此标记。基于Unicode的大小写不敏感的匹配就可以开启了
Pattern.COMMENTS(?x) 在这种模式下,空格符将被忽略掉,并且以#开始直到行末的注释也会被忽略掉。通过嵌入的标记表达式也可以开启Unix的行模式
Pattern.DOTALL(?s) 在dotall模式下,表达式.匹配所有字符,包括行终止符。默认情况下,.不会匹配行终止符
Pattern.MULTILINE(?m) 在多行模式下,表达式^和\(分别匹配一行的开始和结束。^还匹配输入字符串的开始,而\)还匹配输入字符串的结尾。默认情况下,这些表达式仅匹配输入的完整字符串的开始和结束
Pattern.UNICODE_CASE(?u) 当指定这个标记,并且开启CASE_INSENSITIVE时,大小写不敏感的匹配将按照与Unicode标准相一致的方式进行。默认情况下,大小写不敏感的匹配假定只能在US-ASCII字符集中的字符才能进行
Pattern.UNIX_LINES(?d) 在这种模式下,在.、^和$的行为中,只识别行终止符\n

在这些标记中,Pattern.CASE_INSENSITIVEPattern.MULTILINE以及Pattern.COMMENTS(对声明或文档有用)特别有用。请注意,你可以直接在正则表达式中使用其中的大多数标记,只需要将上表中括号括起来的字符插入到正则表达式中,你希望它起作用的位置即可。还可以通过“或”(|)操作符组合多个标记的功能。

Pattern p = Pattern.compile("^java", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);

reset()

通过reset()方法,可以将现有的Matcher对象应用于一个新的字符序列。

扫描输入

Scanner的构造器可以接收任意类型的输入对象,包括File对象、InputStreamString或者Readable实现类。Readable是Java SE5中新加入的一个接口,表示“具有read()方法的某种东西”。

所有的基本类型(除char之外)都有对应的next方法,包括BigDecimal和BigInteger。所有的next方法,只有在找到一个完整的分词之后才会返回。Scanner还有相应的hasNext方法,用以判断下一个输入分词是否是所需的类型,如果是则返回true。

默认情况下,Scanner根据空白字符对输入进行分词,可以用正则表达式指定自己所需的分隔符。可以用useDelimiter()来设置分隔符,同时,还有一个delimiter()方法,用来返回当前正在作为分隔符使用的Pattern对象。

除了能够扫描基本类型之外,还可以使用自定义的正则表达式进行扫描。当next()方法配合指定的正则表达式使用时,将找到下一个匹配该模式的输入部分,调用match()方法就可以获得匹配的结果。在配合正则表达式使用扫描时,有一点需要注意:它仅仅针对下一个输入分词进行匹配,如果你的正则表达式中含有分隔符,那永远不可能匹配成功。

StringTokenizer类

在Java引入正则表达式(J2SE1.4)和Scanner类(Java SE5)之前,分割字符串的唯一方法是使用StringTokenizer来分词。不过,现在有了正则表达式和Scanner,我们可以使用更加简单、更加简洁的方式来完成同样的工作了。

使用正则表达式或Scanner对象,我们能够以更加复杂的模式来分割一个字符串,而这对于StringTokenizer来说就很困难了。基本上,我们可以放心地说,StringTokenizer已经可以废弃不用了。

20190906 On Java8 第十八章 字符串的更多相关文章

  1. 《Linux命令行与shell脚本编程大全》 第十八章 学习笔记

    第十八章:初识sed和gawk 文本处理 sed编辑器 sed编辑器可以基于输入到命令行的或是存储在命令文本文件中的命令来处理数据流中的数据. 它每次读取一行,用提供的编辑器命令匹配数据.按命令中指定 ...

  2. 第十八章 DjangoWeb开发框架

    第十八章 DjangoWeb开发框架 第一课 内容概要: 1.JS正则 -登录注册验证 2.组件 1.BootStrap -css -js 学习BootStrap规则 2.jQueryUI -css ...

  3. Linux内核分析第十八章读书笔记

    第十八章 调试 调试工作艰难是内核级开发区别于用户级开发的一个显著特点. 18.1 准备开始 我们需要什么? 一个bug 一个藏匿bug的内核版本 思路:假定能够让bug重现 在用户级程序中,bug直 ...

  4. Task C# 多线程和异步模型 TPL模型 【C#】43. TPL基础——Task初步 22 C# 第十八章 TPL 并行编程 TPL 和传统 .NET 异步编程一 Task.Delay() 和 Thread.Sleep() 区别

    Task C# 多线程和异步模型 TPL模型   Task,异步,多线程简单总结 1,如何把一个异步封装为Task异步 Task.Factory.FromAsync 对老的一些异步模型封装为Task ...

  5. 《Linux内核设计与实现》读书笔记 第十八章 调试

    第十八章调试 18.1 准备开始          需要准备的东西: l  一个bug:大部分bug通常都不是行为可靠而且定义明确的 l  一个藏匿bug的内核版本:找出bug首先出现的版本 l  相 ...

  6. Python之路【第十八章】:Django基础

    Django基本配置 Python的WEB框架有Django.Tornado.Flask 等多种,Django相较与其他WEB框架其优势为:大而全,框架本身集成了ORM.模型绑定.模板引擎.缓存.Se ...

  7. 《Linux内核设计与实现》课本第十八章自学笔记——20135203齐岳

    <Linux内核设计与实现>课本第十八章自学笔记 By20135203齐岳 通过打印来调试 printk()是内核提供的格式化打印函数,除了和C库提供的printf()函数功能相同外还有一 ...

  8. Gradle 1.12用户指南翻译——第四十八章. Wrapper 插件

    本文由CSDN博客貌似掉线翻译,其他章节的翻译请参见: http://blog.csdn.net/column/details/gradle-translation.html 翻译项目请关注Githu ...

  9. Gradle 1.12 翻译——第十八章. 日志

    有关其他已翻译的章节请关注Github上的项目:https://github.com/msdx/gradledoc/tree/1.12,或访问:http://gradledoc.qiniudn.com ...

随机推荐

  1. github配置及使用

    安装git 对于linux系统,不同发行版本的安装方法不一样,请参考https://git-scm.com/download/linux.以ubuntu为例: sudo add-apt-reposit ...

  2. centos7 安装 tesseract4.1

    官网大法好,其他方法需要装好多依赖,还没安装成功...     yum-config-manager --add-repo https://download.opensuse.org/reposito ...

  3. pandas的settingwithWaring报警

    # 0 读取数据 import pandas as pd df = pd.read_csv("beijing_tianqi_2018.csv") # 换掉温度后面的后缀 df.lo ...

  4. ThinkPHP生成静态页buildHtml方法

    原来ThinkPHP自带了生成静态页的函数buildHtml,使用起来很方便!最新的手册里没写这个方法,向大家介绍一下. PHP 1 2 3 4 5 6 7 8 9 10 11     protect ...

  5. Django【第27篇】:ModelForm

    基于Form组件实现的增删改和基于ModelForm实现的增删改 一.ModelForm的介绍 ModelForm a. class Meta: model, # 对应Model的 fields=No ...

  6. react 详细解析学习笔记

    React的介绍: React来自于Facebook公司的开源项目 React 可以开发单页面应用       spa(单页面应用) react 组件化模块化  开发模式 React通过对DOM的模拟 ...

  7. js倒计时功能中newData().getTime()在iOS下会报错,显示 nan

    最近在做移动端项目 ,有个设置开始时间和结束时间,然后倒计时 这个活动还有几天.在安卓上能正确转换时间,但在iOS上不能显示,为NaN-NaN1-NaN  Invalid Date, 就好比new D ...

  8. Python内置函数之filter map reduce

    Python内置函数之filter map reduce 2013-06-04 Posted by yeho Python内置了一些非常有趣.有用的函数,如:filter.map.reduce,都是对 ...

  9. 02-webpack的作用

    webpack的作用,将不同静态资源的类型打包成一个JS文件,在html页面应用该JS文件的时候,JS文件里的html就可以正常的运行,去执行操作. 也可以加载前端页面的CSS样式.Img图片

  10. CSS定位机制之浮动定位float

    一.浮动定位实现的效果 二.使用float实现浮动定位 三.使用clear属性清除浮动定位 四.浮动定位的应用(布局) 一.浮动定位实现的效果   (一).块元素(div)在文档流中默认垂直排列,如果 ...