简化你的 java 字符串操作:Guava 之 CharMatcher 用法简介

对字符串的处理应该是编程活动中最频繁的操作了,而原生的 JDK 以及 Java 本身的语法特性使得在 Java 中进行字符串操作是一件极其麻烦的事情,如果你熟悉 Shell/Awk/Sed/Perl/Python 等脚本语言,你就大概能明白我说的啥意思了。

上次在这篇使用 Google Guava 美化你的 Java 代码:1~4 中介绍过一些利用 Guava 库进行字符串操作的例子,限于篇幅与内容,介绍的比较泛,今天就单独的聊聊 Guava 中的 CharMatcher 类,并结合一些常见的需求来进行解说。

CharMatcher提供了多种对字符串处理的方法, 它的主要意图有: 1. 找到匹配的字符 2. 处理匹配的字符

CharMatcher 的内部实现主要包括两部分: 1. 实现了大量公用内部类, 用来方便用户对字符串做匹配: 例如 JAVA_DIGIT 匹配数字, JAVA_LETTER 匹配字母等等。 2. 实现了大量处理字符串的方法, 使用特定的CharMatcher可以对匹配到的字符串做出多种处理, 例如 remove(), replace(), trim(), retain()等等。

CharMatcher本身是一个抽象类, 其中一些操作方法是抽象方法, 他主要依靠内部继承CharMatcher的内部子类来实现抽象方法和重写一些操作方法, 因为不同的匹配规则的这些操作方法具有不同的实现要求。

1、默认实现类

CharMatcher本身提供了很多CharMatcher实现类,如下:  ANY: 匹配任何字符 ASCII: 匹配是否是ASCII字符 BREAKING_WHITESPACE: 匹配所有可换行的空白字符(不包括非换行空白字符,例如"\u00a0") DIGIT: 匹配ASCII数字  INVISIBLE: 匹配所有看不见的字符 JAVA_DIGIT: 匹配UNICODE数字, 使用 Character.isDigit() 实现 JAVA_ISO_CONTROL: 匹配ISO控制字符, 使用 Charater.isISOControl() 实现 JAVA_LETTER: 匹配字母, 使用 Charater.isLetter() 实现 JAVA_LETTER_OR_DIGET: 匹配数字或字母 JAVA_LOWER_CASE: 匹配小写 JAVA_UPPER_CASE: 匹配大写 NONE: 不匹配所有字符 SINGLE_WIDTH: 匹配单字宽字符, 如中文字就是双字宽 WHITESPACE: 匹配所有空白字符

2、常用操作方法

CharMatcher is(char match): 返回匹配指定字符的Matcher CharMatcher isNot(char match): 返回不匹配指定字符的Matcher CharMatcher anyOf(CharSequence sequence): 返回匹配sequence中任意字符的Matcher CharMatcher noneOf(CharSequence sequence): 返回不匹配sequence中任何一个字符的Matcher CharMatcher inRange(char startInclusive, char endIncludesive): 返回匹配范围内任意字符的Matcher CharMatcher forPredicate(Predicate<? super Charater> predicate): 返回使用predicate的apply()判断匹配的Matcher CharMatcher negate(): 返回以当前Matcher判断规则相反的Matcher CharMatcher and(CharMatcher other): 返回与other匹配条件组合做与来判断的Matcher CharMatcher or(CharMatcher other): 返回与other匹配条件组合做或来判断的Matcher boolean matchesAnyOf(CharSequence sequence): 只要sequence中有任意字符能匹配Matcher,返回true boolean matchesAllOf(CharSequence sequence): sequence中所有字符都能匹配Matcher,返回true boolean matchesNoneOf(CharSequence sequence): sequence中所有字符都不能匹配Matcher,返回true int indexIn(CharSequence sequence): 返回sequence中匹配到的第一个字符的坐标 int indexIn(CharSequence sequence, int start): 返回从start开始,在sequence中匹配到的第一个字符的坐标 int lastIndexIn(CharSequence sequence): 返回sequence中最后一次匹配到的字符的坐标 int countIn(CharSequence sequence): 返回sequence中匹配到的字符计数 String removeFrom(CharSequence sequence): 删除sequence中匹配到到的字符并返回 String retainFrom(CharSequence sequence): 保留sequence中匹配到的字符并返回 String replaceFrom(CharSequence sequence, char replacement): 替换sequence中匹配到的字符并返回 String trimFrom(CharSequence sequence): 删除首尾匹配到的字符并返回 String trimLeadingFrom(CharSequence sequence): 删除首部匹配到的字符 String trimTrailingFrom(CharSequence sequence): 删除尾部匹配到的字符 String collapseFrom(CharSequence sequence, char replacement): 将匹配到的组(连续匹配的字符)替换成replacement  String trimAndCollapseFrom(CharSequence sequence, char replacement): 先trim在replace

3、一些栗子:

(1)使用预定义的常量 (predefine CharMatcher):

CharMatcher.WHITESPACE (Java whitespace character) CharMatcher.JAVA_DIGIT CharMatcher.JAVA_LETTER CharMatcher.JAVA_LOWER_CASE  CharMatcher.JAVA_UPPER_CASE  CharMatcher.ASCII CharMatcher.ANY ...

String str = "FirstName LastName +1 123 456 789 !@#$%^&*()_+|}{:\"?><";
// Use a predefined constant (predefine CharMatcher) 
CharMatcher.DIGIT.retainFrom(str);
 
Output:->
"1123456789"
 
CharMatcher.JAVA_LETTER.retainFrom(str);
 
Output:->
"FirstNameLastName"
 
CharMatcher.JAVA_LETTER_OR_DIGIT.retainFrom(str);
 
Output:->
"FirstNameLastName1123456789"
 
CharMatcher.ANY.countIn(str)
 
Output:->
54
 
CharMatcher.DIGIT.countIn(str);
 
Output:->
10

(2)使用工厂方法:

CharMatcher.is('x') CharMatcher.isNot('_') CharMatcher.oneOf("aeiou").negate() CharMatcher.inRange('a', 'z').or(inRange('A', 'Z')) ... 使用条件组合:

CharMatcher and(CharMatcher other)  CharMatcher or(CharMatcher other)  CharMatcher negate() 

String str = "FirstName LastName +1 123 456 789 !@#$%^&*()_+|}{:\"?><";
 
CharMatcher.JAVA_LOWER_CASE.negate().retainFrom(str);
Output:->
"FN LN +1 123 456 789 !@#$%^&*()_+|}{:\"?><"
 
CharMatcher.JAVA_DIGIT.or(CharMatcher.anyOf("aeiou")).retainFrom(str);
Output:->
"iaeaae1123456789"

(3)一些小例子:

//原字符串
System.out.println(string);

//去掉控制字符(\t,\n,\b...)
System.out.println(CharMatcher.JAVA_ISO_CONTROL.removeFrom(string));

//获取所有的数字
System.out.println(CharMatcher.DIGIT.retainFrom(string));

//把多个空格替换为一个包括\t,并去掉首位的空格
System.out.println(CharMatcher.WHITESPACE.trimAndCollapseFrom(string, ' '));

//把所有的数字用"*"代替
System.out.println(CharMatcher.JAVA_DIGIT.replaceFrom(string, "*"));

//获取所有的数字和小写字母
System.out.println(CharMatcher.JAVA_DIGIT.or(CharMatcher.JAVA_LOWER_CASE).retainFrom(string));

//获取所有的大写字母
System.out.println(CharMatcher.JAVA_UPPER_CASE.retainFrom(string));

//获取所有单字节长度的符号
System.out.println(CharMatcher.SINGLE_WIDTH.retainFrom(string));
		
/*
原字符串:
  ROCKY  rocky  RoCkY ~!@#$%^&*()      23(*&gS   你好	234啊   GES  

去掉控制字符(\t,\n,\b...):
  ROCKY  rocky  RoCkY ~!@#$%^&*()      23(*&gS   你好234啊   GES  

获取所有的数字:
23234

把多个空格替换为一个包括\t,并去掉首位的空格:
ROCKY rocky RoCkY ~!@#$%^&*() 23(*&gS 你好 234啊 GES

把所有的数字用"*"代替:
  ROCKY  rocky  RoCkY ~!@#$%^&*()      **(*&gS   你好	***啊   GES  

获取所有的数字和小写字母:
rockyok23g234

获取所有的大写字母:
ROCKYRCYSGES

获取所有单字节长度的符号:
  ROCKY  rocky  RoCkY ~!@#$%^&*()      23(*&gS   	234   GES  
*/

(4)用正则作为匹配、判断条件

需要说明的是 CharMatcher 并没有提供以正则表达式作为匹配条件的方法,

你可以参考:

http://stackoverflow.com/questions/12378702/how-to-write-the-charmatcher-equivalent-for-the-regex-word-character

http://blog.csdn.net/firecoder/article/details/5827281  七种武器:Collection 之 Google Guava

不过这个例子貌似只能判断字符,而不是字符串。

但是这难不倒我们,别忘了在上篇文章的最后的链接里,我提到了另一个与 guava 类似的库:Apache Commons,相对而言,它的功能更加完善,比如,这个需求,它内置了一个专门的校验类:Validate

try {
	Validate.matchesPattern("2013-11-241", "\\d{4}-\\d{2}-\\d{2}", "输入的日期格式不正确!");
} catch (Exception e) {
	System.out.println(e.toString());
	// return;
}

// output:
// java.lang.IllegalArgumentException: 输入的日期格式不正确!

所以,我个人倾向于把这两个库结合起来用,这样可以大大节约你的开发时间,降低你的代码冗余度。

好吧,就介绍到这里了,如果你也有这块的心得体会,欢迎交流~

4、Refer:

http://www.cnblogs.com/zemliu/p/3345087.html#top

http://techneerajnandwana.blogspot.com/2011/11/guava-string-manipulation-with.html

http://blog.csdn.net/rocky225/article/details/8289407

http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/index.html

http://commons.apache.org/proper/commons-lang/javadocs/api-release/index.html

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏二进制文集

FastJSON 源码分析

Fastjson是一个Java语言编写的高性能功能完善的JSON库。它采用一种“假定有序快速匹配”的算法,把JSON Parse的性能提升到极致,是目前Java...

1962
来自专栏java学习

请问你知道什么是栈吗?

1.1栈的概念及记本操作 栈(stack)又称堆栈,是限制在表的一端进行插入和删除的线性表。其限制是仅允许在表的一端进行插入和删除操作,不允许在其他任何位置进行...

3168
来自专栏猿人谷

获取对象属性类型、属性名称、属性值的研究:反射和JEXL解析引擎

先简单介绍下反射的概念:java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动...

1.3K5
来自专栏个人分享

Scala第一章学习笔记

  面向对象编程是一种自顶向下的程序设计方法。用面向对象方法构造软件时,我们将代码以名词(对象)做切割,每个对象有某种形式的表示服(self/this)、行为(...

1062
来自专栏Golang语言社区

【Go 语言社区】POJ 1047 Round and Round We Go 循环数新解

题目描述: 给定一字符串表示的高精度数,判断它是否是可循环的。如果假设字符串num的长为n,则将num从1开始乘到n,如果每次得到的结果包含的字符元素都和a是相...

35711
来自专栏算法修养

PAT 甲级 1060 Are They Equal

1060. Are They Equal (25) 时间限制 50 ms 内存限制 65536 kB 代码长度限制 16000 B ...

2995
来自专栏行者常至

020.Java的反射机制

JAVA反射机制是在运行状态中, 对于任意一个类,都能够知道这个类的所有属性和方法; 对于任意一个对象,都能够调用它的任意方法和属性; 这种动态获取信息以...

831
来自专栏屈定‘s Blog

Java8 Lambda(一)-函数式接口

实习前只是粗略的看了下Java8的一些基本语法,但是没有系统的学习过.在使用一段时间后决定系统的对其进行一次分析,加深对Java8函数式编程的理解,提高自己的编...

4373
来自专栏calmound

UVA Hangman Judge

英语太烂啊。 In ``Hangman Judge,'' you are to write a program that judges a series of ...

3307
来自专栏李蔚蓬的专栏

Java基础知识的全面巩固_note1(附各种demo code)

上面的cmd中,javac程序是一个Java编译器,它将文件Welcome.java编译成Welcome.class.java程序启动Java虚拟机。虚拟机执行...

912

扫码关注云+社区

领取腾讯云代金券