使用示例时须导入以下jar包进行测试,guava版本使用28.2-jre
。
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>28.2-jre</version>
</dependency>
<dependency>
<groupId>com.google.truth</groupId>
<artifactId>truth</artifactId>
<version>1.0.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava-testlib</artifactId>
<version>28.2-jre</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
<scope>compile</scope>
</dependency>
Strings:一些非常有用的字符串工具:拆分,连接,填充等。
1.Ascii字符
与ASCII字符(值在
0x00
至0x7F
范围内的字符)有关的静态方法,以及包含此类字符的字符串。
1.1判断是否小写
方法:boolean isLowerCase(char c)
指示c是否为’a’和’z’之间的26个小写ASCII字母字符之一。所有其他字符(包括非ASCII字符)都返回false。
1.2判断是否大写
方法:boolean isUpperCase(char c)
指示c是否为’A’和’Z’之间的26个小写ASCII字母字符之一。所有其他字符(包括非ASCII字符)都返回false。
1.3返回小写
方法:char toLowerCase(char c)
如果参数为
isUpperCase(char)
大写ASCII字符,则返回等效的小写字母。否则返回参数。
方法:String toLowerCase(CharSequence chars)
返回输入字符序列的副本,其中所有
isUpperCase(char)
大写ASCII字符都已转换为小写。所有其他字符均被复制而没有修改。
方法:String toLowerCase(String string)
返回输入字符串的副本,其中所有
isUpperCase(char)
大写ASCII字符都已转换为小写。所有其他字符均被复制而没有修改。
1.4返回大写
参见上一节
1.5忽略大小写判断
方法:boolean equalsIgnoreCase(CharSequence s1, CharSequence s2)
指示给定字符序列
s1
和s2
的内容是否相等,而忽略'a'
和'z'
或'A'
和'Z'
(含)之间的任何ASCII字母字符的情况。
此方法比String#equalsIgnoreCase
明显快得多,如果已知至少一个参数仅包含ASCII字符,则应优先使用此方法。
但是请注意,此方法的行为并不总是与以下表达式相同:string.toUpperCase().equals("UPPER CASE ASCII") string.toLowerCase().equals("lower case ascii")
由于某些非ASCII字符的大小写折叠(在
String#equalsIgnoreCase
中不会发生)。但是,在几乎所有使用ASCII字符串的情况下,作者都可能希望此方法提供的行为,而不是toUpperCase()
和toLowerCase()
的微妙且有时令人惊讶的行为。
1.6截断
方法:String truncate(CharSequence seq, int maxLength, String truncationIndicator)
将给定的字符序列截断为给定的最大长度。如果序列的长度大于
maxLength
,则返回的字符串> 的长度将精确为maxLength
个字符,并以给定的truncationIndicator
结尾。否则,序> > 列将以字符串形式返回,且内容不变。示例:
Ascii.truncate("foobar", 7, "..."); // returns "foobar" Ascii.truncate("foobar", 5, "..."); // returns "fo..."
注意: 此方法可以用于某些非ASCII文本,但与任意Unicode文本一起使用不安全。它主要用于与已知可以安全使用的文本(例如,全ASCII文本)和简单的调试文本一起使用。使用此方法时,请考虑以下事项:
- 它可能会拆分代理对
- 它可以分割字符并组合字符
- 它不考虑单词边界
- 如果要截断以显示给用户,则必须考虑其他因素
- 适当的截断指示符可能取决于语言环境
- 在截断指示器中使用非ASCII字符是安全的
如果
maxLength
小于truncationIndicator
的长度,则throws IllegalArgumentException
1.7使用示例
import com.google.common.annotations.GwtIncompatible;
import com.google.common.base.Ascii;
import junit.framework.TestCase;
public class AsciiTest extends TestCase {
/**
* The Unicode points {@code 00c1} and {@code 00e1} are the upper- and lowercase forms of
* A-with-acute-accent, {@code Á} and {@code á}.
*/
private static final String IGNORED = "`10-=~!@#$%^&*()_+[]\\{}|;':\",./<>?'\u00c1\u00e1\n";
private static final String LOWER = "abcdefghijklmnopqrstuvwxyz";
private static final String UPPER = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
public void testToLowerCase() {
assertEquals(LOWER, Ascii.toLowerCase(UPPER));
assertSame(LOWER, Ascii.toLowerCase(LOWER));
assertEquals(IGNORED, Ascii.toLowerCase(IGNORED));
assertEquals("foobar", Ascii.toLowerCase("fOobaR"));
}
public void testToUpperCase() {
assertEquals(UPPER, Ascii.toUpperCase(LOWER));
assertSame(UPPER, Ascii.toUpperCase(UPPER));
assertEquals(IGNORED, Ascii.toUpperCase(IGNORED));
assertEquals("FOOBAR", Ascii.toUpperCase("FoOBAr"));
}
public void testCharsIgnored() {
for (char c : IGNORED.toCharArray()) {
String str = String.valueOf(c);
assertTrue(str, c == Ascii.toLowerCase(c));
assertTrue(str, c == Ascii.toUpperCase(c));
assertFalse(str, Ascii.isLowerCase(c));
assertFalse(str, Ascii.isUpperCase(c));
}
}
public void testCharsLower() {
for (char c : LOWER.toCharArray()) {
String str = String.valueOf(c);
assertTrue(str, c == Ascii.toLowerCase(c));
assertFalse(str, c == Ascii.toUpperCase(c));
assertTrue(str, Ascii.isLowerCase(c));
assertFalse(str, Ascii.isUpperCase(c));
}
}
public void testCharsUpper() {
for (char c : UPPER.toCharArray()) {
String str = String.valueOf(c);
assertFalse(str, c == Ascii.toLowerCase(c));
assertTrue(str, c == Ascii.toUpperCase(c));
assertFalse(str, Ascii.isLowerCase(c));
assertTrue(str, Ascii.isUpperCase(c));
}
}
public void testTruncate() {
assertEquals("foobar", Ascii.truncate("foobar", 10, "..."));
assertEquals("fo...", Ascii.truncate("foobar", 5, "..."));
assertEquals("foobar", Ascii.truncate("foobar", 6, "..."));
assertEquals("...", Ascii.truncate("foobar", 3, "..."));
assertEquals("foobar", Ascii.truncate("foobar", 10, "…"));
assertEquals("foo…", Ascii.truncate("foobar", 4, "…"));
assertEquals("fo--", Ascii.truncate("foobar", 4, "--"));
assertEquals("foobar", Ascii.truncate("foobar", 6, "…"));
assertEquals("foob…", Ascii.truncate("foobar", 5, "…"));
assertEquals("foo", Ascii.truncate("foobar", 3, ""));
assertEquals("", Ascii.truncate("", 5, ""));
assertEquals("", Ascii.truncate("", 5, "..."));
assertEquals("", Ascii.truncate("", 0, ""));
}
public void testTruncateIllegalArguments() {
String truncated = null;
try {
truncated = Ascii.truncate("foobar", 2, "...");
fail();
} catch (IllegalArgumentException expected) {
}
try {
truncated = Ascii.truncate("foobar", 8, "1234567890");
fail();
} catch (IllegalArgumentException expected) {
}
try {
truncated = Ascii.truncate("foobar", -1, "...");
fail();
} catch (IllegalArgumentException expected) {
}
try {
truncated = Ascii.truncate("foobar", -1, "");
fail();
} catch (IllegalArgumentException expected) {
}
}
public void testEqualsIgnoreCase() {
assertTrue(Ascii.equalsIgnoreCase("", ""));
assertFalse(Ascii.equalsIgnoreCase("", "x"));
assertFalse(Ascii.equalsIgnoreCase("x", ""));
assertTrue(Ascii.equalsIgnoreCase(LOWER, UPPER));
assertTrue(Ascii.equalsIgnoreCase(UPPER, LOWER));
// Create new strings here to avoid early-out logic.
assertTrue(Ascii.equalsIgnoreCase(new String(IGNORED), new String(IGNORED)));
// Compare to: "\u00c1".equalsIgnoreCase("\u00e1") == true
assertFalse(Ascii.equalsIgnoreCase("\u00c1", "\u00e1"));
// Test chars just outside the alphabetic range ('A'-1 vs 'a'-1, 'Z'+1 vs 'z'+1)
assertFalse(Ascii.equalsIgnoreCase("@", "`"));
assertFalse(Ascii.equalsIgnoreCase("[", "{"));
}
@GwtIncompatible // String.toUpperCase() has browser semantics
public void testEqualsIgnoreCaseUnicodeEquivalence() {
// Note that it's possible in future that the JDK's idea to toUpperCase() or equalsIgnoreCase()
// may change and break assumptions in this test [*]. This is not a bug in the implementation of
// Ascii.equalsIgnoreCase(), but it is a signal that its documentation may need updating as
// regards edge cases.
// The Unicode point {@code 00df} is the lowercase form of sharp-S (ß), whose uppercase is "SS".
assertEquals("PASSWORD", "pa\u00dfword".toUpperCase()); // [*]
assertFalse("pa\u00dfword".equalsIgnoreCase("PASSWORD")); // [*]
assertFalse(Ascii.equalsIgnoreCase("pa\u00dfword", "PASSWORD"));
}
}
2.CaseFormat大小写格式
在各种ASCII大小写格式之间进行转换的实用程序类。对于非ASCII输入,行为未定义。
CaseFormat
是一个方便的枚举类,用于在ASCII大小写约定之间进行转换——例如,编程语言的命名约定。支持的格式包括:
枚举 | 说明 | 描述 |
---|---|---|
LOWER_HYPHEN | 小写连字符 | 连字符的变量命名约定,例如"lower-hyphen" |
LOWER_UNDERSCORE | 全小写下划线 | C++变量命名约定,例如"lower_underscore" |
LOWER_CAMEL | 小写驼峰 | Java变量命名约定,例如"lowerCamel" |
UPPER_CAMEL | 大写驼峰 | Java和C++类的命名约定,例如"UpperCamel" |
UPPER_UNDERSCORE | 全大写下划线 | Java和C++常量命名约定,例如"UPPER_UNDERSCORE" |
使用它相对简单:
CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, "CONSTANT_NAME")); // returns "constantName"
例如,在编写代码生成器时,我们发现这特别有用。
2.1to转换
方法:String to(CaseFormat format, String str)
将指定的
String str
从此格式转换为指定的format
格式。采取“尽力而为”的方法;如果str
不符合假定的格式,则此方法的行为未定义,但无论如何我们都会做出合理的努力。
2.2converterTo转换
方法:Converter<String, String> converterTo(CaseFormat targetFormat)
返回一个
Converter
,它将字符串从此格式转换为目标格式targetFormat
。
2.3使用示例
import com.google.common.annotations.GwtIncompatible;
import com.google.common.base.CaseFormat;
import com.google.common.testing.NullPointerTester;
import com.google.common.testing.SerializableTester;
import junit.framework.TestCase;
import static com.google.common.base.CaseFormat.*;
public class CaseFormatTest extends TestCase {
public void testIdentity() {
for (CaseFormat from : CaseFormat.values()) {
assertSame(from + " to " + from, "foo", from.to(from, "foo"));
for (CaseFormat to : CaseFormat.values()) {
assertEquals(from + " to " + to, "", from.to(to, ""));
assertEquals(from + " to " + to, " ", from.to(to, " "));
}
}
}
@GwtIncompatible // NullPointerTester
public void testNullArguments() {
NullPointerTester tester = new NullPointerTester();
tester.testAllPublicStaticMethods(CaseFormat.class);
for (CaseFormat format : CaseFormat.values()) {
tester.testAllPublicInstanceMethods(format);
}
}
public void testLowerHyphenToLowerHyphen() {
assertEquals("foo", LOWER_HYPHEN.to(LOWER_HYPHEN, "foo"));
assertEquals("foo-bar", LOWER_HYPHEN.to(LOWER_HYPHEN, "foo-bar"));
}
public void testLowerHyphenToLowerUnderscore() {
assertEquals("foo", LOWER_HYPHEN.to(LOWER_UNDERSCORE, "foo"));
assertEquals("foo_bar", LOWER_HYPHEN.to(LOWER_UNDERSCORE, "foo-bar"));
}
public void testLowerHyphenToLowerCamel() {
assertEquals("foo", LOWER_HYPHEN.to(LOWER_CAMEL, "foo"));
assertEquals("fooBar", LOWER_HYPHEN.to(LOWER_CAMEL, "foo-bar"));
}
public void testLowerHyphenToUpperCamel() {
assertEquals("Foo", LOWER_HYPHEN.to(UPPER_CAMEL, "foo"));
assertEquals("FooBar", LOWER_HYPHEN.to(UPPER_CAMEL, "foo-bar"));
}
public void testLowerHyphenToUpperUnderscore() {
assertEquals("FOO", LOWER_HYPHEN.to(UPPER_UNDERSCORE, "foo"));
assertEquals("FOO_BAR", LOWER_HYPHEN.to(UPPER_UNDERSCORE, "foo-bar"));
}
public void testLowerUnderscoreToLowerHyphen() {
assertEquals("foo", LOWER_UNDERSCORE.to(LOWER_HYPHEN, "foo"));
assertEquals("foo-bar", LOWER_UNDERSCORE.to(LOWER_HYPHEN, "foo_bar"));
}
public void testLowerUnderscoreToLowerUnderscore() {
assertEquals("foo", LOWER_UNDERSCORE.to(LOWER_UNDERSCORE, "foo"));
assertEquals("foo_bar", LOWER_UNDERSCORE.to(LOWER_UNDERSCORE, "foo_bar"));
}
public void testLowerUnderscoreToLowerCamel() {
assertEquals("foo", LOWER_UNDERSCORE.to(LOWER_CAMEL, "foo"));
assertEquals("fooBar", LOWER_UNDERSCORE.to(LOWER_CAMEL, "foo_bar"));
}
public void testLowerUnderscoreToUpperCamel() {
assertEquals("Foo", LOWER_UNDERSCORE.to(UPPER_CAMEL, "foo"));
assertEquals("FooBar", LOWER_UNDERSCORE.to(UPPER_CAMEL, "foo_bar"));
}
public void testLowerUnderscoreToUpperUnderscore() {
assertEquals("FOO", LOWER_UNDERSCORE.to(UPPER_UNDERSCORE, "foo"));
assertEquals("FOO_BAR", LOWER_UNDERSCORE.to(UPPER_UNDERSCORE, "foo_bar"));
}
public void testLowerCamelToLowerHyphen() {
assertEquals("foo", LOWER_CAMEL.to(LOWER_HYPHEN, "foo"));
assertEquals("foo-bar", LOWER_CAMEL.to(LOWER_HYPHEN, "fooBar"));
assertEquals("h-t-t-p", LOWER_CAMEL.to(LOWER_HYPHEN, "HTTP"));
}
public void testLowerCamelToLowerUnderscore() {
assertEquals("foo", LOWER_CAMEL.to(LOWER_UNDERSCORE, "foo"));
assertEquals("foo_bar", LOWER_CAMEL.to(LOWER_UNDERSCORE, "fooBar"));
assertEquals("h_t_t_p", LOWER_CAMEL.to(LOWER_UNDERSCORE, "hTTP"));
}
public void testLowerCamelToLowerCamel() {
assertEquals("foo", LOWER_CAMEL.to(LOWER_CAMEL, "foo"));
assertEquals("fooBar", LOWER_CAMEL.to(LOWER_CAMEL, "fooBar"));
}
public void testLowerCamelToUpperCamel() {
assertEquals("Foo", LOWER_CAMEL.to(UPPER_CAMEL, "foo"));
assertEquals("FooBar", LOWER_CAMEL.to(UPPER_CAMEL, "fooBar"));
assertEquals("HTTP", LOWER_CAMEL.to(UPPER_CAMEL, "hTTP"));
}
public void testLowerCamelToUpperUnderscore() {
assertEquals("FOO", LOWER_CAMEL.to(UPPER_UNDERSCORE, "foo"));
assertEquals("FOO_BAR", LOWER_CAMEL.to(UPPER_UNDERSCORE, "fooBar"));
}
public void testUpperCamelToLowerHyphen() {
assertEquals("foo", UPPER_CAMEL.to(LOWER_HYPHEN, "Foo"));
assertEquals("foo-bar", UPPER_CAMEL.to(LOWER_HYPHEN, "FooBar"));
}
public void testUpperCamelToLowerUnderscore() {
assertEquals("foo", UPPER_CAMEL.to(LOWER_UNDERSCORE, "Foo"));
assertEquals("foo_bar", UPPER_CAMEL.to(LOWER_UNDERSCORE, "FooBar"));
}
public void testUpperCamelToLowerCamel() {
assertEquals("foo", UPPER_CAMEL.to(LOWER_CAMEL, "Foo"));
assertEquals("fooBar", UPPER_CAMEL.to(LOWER_CAMEL, "FooBar"));
assertEquals("hTTP", UPPER_CAMEL.to(LOWER_CAMEL, "HTTP"));
}
public void testUpperCamelToUpperCamel() {
assertEquals("Foo", UPPER_CAMEL.to(UPPER_CAMEL, "Foo"));
assertEquals("FooBar", UPPER_CAMEL.to(UPPER_CAMEL, "FooBar"));
}
public void testUpperCamelToUpperUnderscore() {
assertEquals("FOO", UPPER_CAMEL.to(UPPER_UNDERSCORE, "Foo"));
assertEquals("FOO_BAR", UPPER_CAMEL.to(UPPER_UNDERSCORE, "FooBar"));
assertEquals("H_T_T_P", UPPER_CAMEL.to(UPPER_UNDERSCORE, "HTTP"));
assertEquals("H__T__T__P", UPPER_CAMEL.to(UPPER_UNDERSCORE, "H_T_T_P"));
}
public void testUpperUnderscoreToLowerHyphen() {
assertEquals("foo", UPPER_UNDERSCORE.to(LOWER_HYPHEN, "FOO"));
assertEquals("foo-bar", UPPER_UNDERSCORE.to(LOWER_HYPHEN, "FOO_BAR"));
}
public void testUpperUnderscoreToLowerUnderscore() {
assertEquals("foo", UPPER_UNDERSCORE.to(LOWER_UNDERSCORE, "FOO"));
assertEquals("foo_bar", UPPER_UNDERSCORE.to(LOWER_UNDERSCORE, "FOO_BAR"));
}
public void testUpperUnderscoreToLowerCamel() {
assertEquals("foo", UPPER_UNDERSCORE.to(LOWER_CAMEL, "FOO"));
assertEquals("fooBar", UPPER_UNDERSCORE.to(LOWER_CAMEL, "FOO_BAR"));
}
public void testUpperUnderscoreToUpperCamel() {
assertEquals("Foo", UPPER_UNDERSCORE.to(UPPER_CAMEL, "FOO"));
assertEquals("FooBar", UPPER_UNDERSCORE.to(UPPER_CAMEL, "FOO_BAR"));
assertEquals("HTTP", UPPER_UNDERSCORE.to(UPPER_CAMEL, "H_T_T_P"));
}
public void testUpperUnderscoreToUpperUnderscore() {
assertEquals("FOO", UPPER_UNDERSCORE.to(UPPER_UNDERSCORE, "FOO"));
assertEquals("FOO_BAR", UPPER_UNDERSCORE.to(UPPER_UNDERSCORE, "FOO_BAR"));
}
public void testConverterToForward() {
assertEquals("FooBar", UPPER_UNDERSCORE.converterTo(UPPER_CAMEL).convert("FOO_BAR"));
assertEquals("fooBar", UPPER_UNDERSCORE.converterTo(LOWER_CAMEL).convert("FOO_BAR"));
assertEquals("FOO_BAR", UPPER_CAMEL.converterTo(UPPER_UNDERSCORE).convert("FooBar"));
assertEquals("FOO_BAR", LOWER_CAMEL.converterTo(UPPER_UNDERSCORE).convert("fooBar"));
}
public void testConverterToBackward() {
assertEquals("FOO_BAR", UPPER_UNDERSCORE.converterTo(UPPER_CAMEL).reverse().convert("FooBar"));
assertEquals("FOO_BAR", UPPER_UNDERSCORE.converterTo(LOWER_CAMEL).reverse().convert("fooBar"));
assertEquals("FooBar", UPPER_CAMEL.converterTo(UPPER_UNDERSCORE).reverse().convert("FOO_BAR"));
assertEquals("fooBar", LOWER_CAMEL.converterTo(UPPER_UNDERSCORE).reverse().convert("FOO_BAR"));
}
public void testConverter_nullConversions() {
for (CaseFormat outer : CaseFormat.values()) {
for (CaseFormat inner : CaseFormat.values()) {
assertNull(outer.converterTo(inner).convert(null));
assertNull(outer.converterTo(inner).reverse().convert(null));
}
}
}
public void testConverter_toString() {
assertEquals(
"LOWER_HYPHEN.converterTo(UPPER_CAMEL)", LOWER_HYPHEN.converterTo(UPPER_CAMEL).toString());
}
public void testConverter_serialization() {
for (CaseFormat outer : CaseFormat.values()) {
for (CaseFormat inner : CaseFormat.values()) {
SerializableTester.reserializeAndAssert(outer.converterTo(inner));
}
}
}
}
3.CharMatcher字符匹配器
确定任何Java中
char
值是真还是假,就像Predicate
对任何Object
所做的一样。还提供了基于此函数的基本文本处理方法。强烈建议实现的过程必须无副作用且不可变。在此类的整个文档中,短语“匹配字符”用于表示"任何
char
值c
,其中this.matches(c)
返回true
"。警告: 此类仅处理
char
值,即BMP字符。它不理解0x10000
到0x10FFFF
范围内的补充Unicode代码点,该范围包括大多数分配的字符,包括重要的CJK
字符和表情符号。补充字符使用代理对编码为
String
,而CharMatcher
将这些字符视为两个单独的字符。countIn
将每个补充字符计为2个char
s。对于最新的Unicode字符属性(数字,字母等)并支持补充代码点,请使用
ICU4J UCharacter
和UnicodeSet
(构建后为freeze())。对于基于UnicodeSet
的基本文本处理,请使用ICU4J UnicodeSetSpanner
。使用示例:
String trimmed = whitespace().trimFrom(userInput); if (ascii().matchesAllOf(s)) { ... }
在过去,我们的StringUtil
类不受控制地增长,并且具有许多类似这样的方法:
allAscii
、collapse
、collapseControlChars
、collapseWhitespace
、lastIndexNotOf
、numSharedChars
、removeChars
、removeCrLf
、retainAllChars
、strip
、stripAndCollapse
、stripNonDigits
它们代表两个概念的部分交叉:
- 什么构成“匹配”字符?
- 如何处理这些“匹配”的字符?
为了简化这一难题,开发了CharMatcher
。
直观地,可以将CharMatcher
视为代表特定类别的字符,例如数字或空格。实际上,CharMatcher
只是有关字符的布尔谓词——事实上,CharMatcher
实现了[Predicate<Character>
]——但是由于引用“所有空白字符”或“所有小写字母”太普遍了,因此Guava提供了专门的字符语法和API。
但是CharMatcher
的实用工具包含在操作中,它使你可以在出现指定类别的字符时执行:修剪[trimming],折叠[collapsing],移除[removing],保留[retaining]等等。CharMatcher
类型的对象表示概念1:什么构成匹配字符?然后,它提供了许多回答概念2的操作:如何处理这些匹配的字符?结果是,API复杂度呈线性增加,而灵活性和功能则成倍增加。好极了!
String noControl = CharMatcher.javaIsoControl().removeFrom(string); // remove control characters
String theDigits = CharMatcher.digit().retainFrom(string); // only the digits
String spaced = CharMatcher.whitespace().trimAndCollapseFrom(string, ' ');
// trim whitespace at ends, and replace/collapse whitespace into single spaces
String noDigits = CharMatcher.javaDigit().replaceFrom(string, "*"); // star out all digits
String lowerAndDigit = CharMatcher.javaDigit().or(CharMatcher.javaLowerCase()).retainFrom(string);
// eliminate all characters that aren't digits or lowercase
注意: CharMatcher
仅处理char
值;它不能理解0x10000
到0x10FFFF
范围内的补充Unicode代码点。使用代理对将此类逻辑字符编码为String
,并且CharMatcher
将这些字符视为两个单独的字符。
3.1获取字符匹配器
提供的CharMatcher工厂方法可以满足许多需求:
any()
none()
whitespace()
breakingWhitespace()
invisible()
digit()
javaLetter()
javaDigit()
javaLetterOrDigit()
javaIsoControl()
javaLowerCase()
javaUpperCase()
ascii()
singleWidth()
获取CharMatcher
的其它常见方法包括:
方法 | 描述 |
---|---|
anyOf(CharSequence) | 指定希望匹配的所有字符。例如,CharMatcher.anyOf("aeiou")匹配小写英语元音。 |
is(char) | 仅指定一个字符进行匹配。 |
inRange(char,char) | 指定要匹配的字符范围,示例:CharMatcher.inRange('a','z')。 |
此外,CharMatcher
具有negate()
,and(CharMatcher)
和or(CharMatcher)
。这些在CharMatcher
上提供了简单的布尔操作。
3.2使用字符匹配器
CharMatcher
提供了多种多样方法来处理任何CharSequence
中出现的指定字符。提供的方法比我们在此处列出的方法更多,但是一些最常用的方法是:
方法 | 描述 |
---|---|
collapseFrom(CharSequence,char) | 将每组连续匹配的字符替换为指定的字符。例如,WHITESPACE.collapseFrom(string,'')将空格折叠为单个空格。 |
matchesAllOf(CharSequence) | 测试此匹配器是否匹配序列中的所有字符。例如,ASCII.matchesAllOf(string)测试字符串中的所有字符是否均为ASCII。 |
removeFrom(CharSequence) | 从序列中删除匹配的字符。 |
retainFrom(CharSequence) | 从序列中删除所有不匹配的字符。 |
trimFrom(CharSequence) | 删除开头和结尾的匹配字符。 |
replaceFrom(CharSequence,CharSequence) | 用给定的序列替换匹配的字符。 |
(注意:所有这些方法都返回一个String
,但matchesAllOf
除外,后者返回一个boolean
布尔值。)
3.3使用示例
import com.google.common.annotations.GwtIncompatible;
import com.google.common.base.CharMatcher;
import com.google.common.base.Predicates;
import com.google.common.base.Strings;
import com.google.common.testing.NullPointerTester;
import junit.framework.AssertionFailedError;
import junit.framework.TestCase;
import static com.google.common.base.CharMatcher.*;
public class CharMatcherTest extends TestCase {
@GwtIncompatible // NullPointerTester
public void testStaticNullPointers() throws Exception {
NullPointerTester tester = new NullPointerTester();
tester.testAllPublicStaticMethods(CharMatcher.class);
tester.testAllPublicInstanceMethods(CharMatcher.any());
tester.testAllPublicInstanceMethods(anyOf("abc"));
}
private static final CharMatcher WHATEVER =
new CharMatcher() {
@Override
public boolean matches(char c) {
throw new AssertionFailedError("You weren't supposed to actually invoke me!");
}
};
public void testAnyAndNone_logicalOps() throws Exception {
// These are testing behavior that's never promised by the API, but since
// we're lucky enough that these do pass, it saves us from having to write
// more excruciating tests! Hooray!
assertSame(CharMatcher.any(), CharMatcher.none().negate());
assertSame(CharMatcher.none(), CharMatcher.any().negate());
assertSame(WHATEVER, CharMatcher.any().and(WHATEVER));
assertSame(CharMatcher.any(), CharMatcher.any().or(WHATEVER));
assertSame(CharMatcher.none(), CharMatcher.none().and(WHATEVER));
assertSame(WHATEVER, CharMatcher.none().or(WHATEVER));
}
// The rest of the behavior of ANY and DEFAULT will be covered in the tests for
// the text processing methods below.
public void testWhitespaceBreakingWhitespaceSubset() throws Exception {
for (int c = 0; c <= Character.MAX_VALUE; c++) {
if (breakingWhitespace().matches((char) c)) {
assertTrue(Integer.toHexString(c), whitespace().matches((char) c));
}
}
}
// The next tests require ICU4J and have, at least for now, been sliced out
// of the open-source view of the tests.
@GwtIncompatible // Character.isISOControl
public void testJavaIsoControl() {
for (int c = 0; c <= Character.MAX_VALUE; c++) {
assertEquals(
"" + c, Character.isISOControl(c), CharMatcher.javaIsoControl().matches((char) c));
}
}
// Omitting tests for the rest of the JAVA_* constants as these are defined
// as extremely straightforward pass-throughs to the JDK methods.
// We're testing the is(), isNot(), anyOf(), noneOf() and inRange() methods
// below by testing their text-processing methods.
// The organization of this test class is unusual, as it's not done by
// method, but by overall "scenario". Also, the variety of actual tests we
// do borders on absurd overkill. Better safe than sorry, though?
public void testEmpty() throws Exception {
doTestEmpty(CharMatcher.any());
doTestEmpty(CharMatcher.none());
doTestEmpty(is('a'));
doTestEmpty(isNot('a'));
doTestEmpty(anyOf(""));
doTestEmpty(anyOf("x"));
doTestEmpty(anyOf("xy"));
doTestEmpty(anyOf("CharMatcher"));
doTestEmpty(noneOf("CharMatcher"));
doTestEmpty(inRange('n', 'q'));
doTestEmpty(forPredicate(Predicates.equalTo('c')));
}
@GwtIncompatible // NullPointerTester
public void testNull() throws Exception {
doTestNull(CharMatcher.any());
doTestNull(CharMatcher.none());
doTestNull(is('a'));
doTestNull(isNot('a'));
doTestNull(anyOf(""));
doTestNull(anyOf("x"));
doTestNull(anyOf("xy"));
doTestNull(anyOf("CharMatcher"));
doTestNull(noneOf("CharMatcher"));
doTestNull(inRange('n', 'q'));
doTestNull(forPredicate(Predicates.equalTo('c')));
}
private void doTestEmpty(CharMatcher matcher) throws Exception {
reallyTestEmpty(matcher);
reallyTestEmpty(matcher.negate());
reallyTestEmpty(matcher.precomputed());
}
private void reallyTestEmpty(CharMatcher matcher) throws Exception {
assertEquals(-1, matcher.indexIn(""));
assertEquals(-1, matcher.indexIn("", 0));
try {
matcher.indexIn("", 1);
fail();
} catch (IndexOutOfBoundsException expected) {
}
try {
matcher.indexIn("", -1);
fail();
} catch (IndexOutOfBoundsException expected) {
}
assertEquals(-1, matcher.lastIndexIn(""));
assertFalse(matcher.matchesAnyOf(""));
assertTrue(matcher.matchesAllOf(""));
assertTrue(matcher.matchesNoneOf(""));
assertEquals("", matcher.removeFrom(""));
assertEquals("", matcher.replaceFrom("", 'z'));
assertEquals("", matcher.replaceFrom("", "ZZ"));
assertEquals("", matcher.trimFrom(""));
assertEquals(0, matcher.countIn(""));
}
@GwtIncompatible // NullPointerTester
private static void doTestNull(CharMatcher matcher) throws Exception {
NullPointerTester tester = new NullPointerTester();
tester.testAllPublicInstanceMethods(matcher);
}
public void testNoMatches() {
doTestNoMatches(CharMatcher.none(), "blah");
doTestNoMatches(is('a'), "bcde");
doTestNoMatches(isNot('a'), "aaaa");
doTestNoMatches(anyOf(""), "abcd");
doTestNoMatches(anyOf("x"), "abcd");
doTestNoMatches(anyOf("xy"), "abcd");
doTestNoMatches(anyOf("CharMatcher"), "zxqy");
doTestNoMatches(noneOf("CharMatcher"), "ChMa");
doTestNoMatches(inRange('p', 'x'), "mom");
doTestNoMatches(forPredicate(Predicates.equalTo('c')), "abe");
doTestNoMatches(inRange('A', 'Z').and(inRange('F', 'K').negate()), "F1a");
doTestNoMatches(CharMatcher.digit(), "\tAz()");
doTestNoMatches(CharMatcher.javaDigit(), "\tAz()");
doTestNoMatches(CharMatcher.digit().and(CharMatcher.ascii()), "\tAz()");
doTestNoMatches(CharMatcher.singleWidth(), "\u05bf\u3000");
}
private void doTestNoMatches(CharMatcher matcher, String s) {
reallyTestNoMatches(matcher, s);
reallyTestAllMatches(matcher.negate(), s);
reallyTestNoMatches(matcher.precomputed(), s);
reallyTestAllMatches(matcher.negate().precomputed(), s);
reallyTestAllMatches(matcher.precomputed().negate(), s);
reallyTestNoMatches(forPredicate(matcher), s);
reallyTestNoMatches(matcher, new StringBuilder(s));
}
public void testAllMatches() {
doTestAllMatches(CharMatcher.any(), "blah");
doTestAllMatches(isNot('a'), "bcde");
doTestAllMatches(is('a'), "aaaa");
doTestAllMatches(noneOf("CharMatcher"), "zxqy");
doTestAllMatches(anyOf("x"), "xxxx");
doTestAllMatches(anyOf("xy"), "xyyx");
doTestAllMatches(anyOf("CharMatcher"), "ChMa");
doTestAllMatches(inRange('m', 'p'), "mom");
doTestAllMatches(forPredicate(Predicates.equalTo('c')), "ccc");
doTestAllMatches(CharMatcher.digit(), "0123456789\u0ED0\u1B59");
doTestAllMatches(CharMatcher.javaDigit(), "0123456789");
doTestAllMatches(CharMatcher.digit().and(CharMatcher.ascii()), "0123456789");
doTestAllMatches(CharMatcher.singleWidth(), "\t0123ABCdef~\u00A0\u2111");
}
private void doTestAllMatches(CharMatcher matcher, String s) {
reallyTestAllMatches(matcher, s);
reallyTestNoMatches(matcher.negate(), s);
reallyTestAllMatches(matcher.precomputed(), s);
reallyTestNoMatches(matcher.negate().precomputed(), s);
reallyTestNoMatches(matcher.precomputed().negate(), s);
reallyTestAllMatches(forPredicate(matcher), s);
reallyTestAllMatches(matcher, new StringBuilder(s));
}
private void reallyTestNoMatches(CharMatcher matcher, CharSequence s) {
assertFalse(matcher.matches(s.charAt(0)));
assertEquals(-1, matcher.indexIn(s));
assertEquals(-1, matcher.indexIn(s, 0));
assertEquals(-1, matcher.indexIn(s, 1));
assertEquals(-1, matcher.indexIn(s, s.length()));
try {
matcher.indexIn(s, s.length() + 1);
fail();
} catch (IndexOutOfBoundsException expected) {
}
try {
matcher.indexIn(s, -1);
fail();
} catch (IndexOutOfBoundsException expected) {
}
assertEquals(-1, matcher.lastIndexIn(s));
assertFalse(matcher.matchesAnyOf(s));
assertFalse(matcher.matchesAllOf(s));
assertTrue(matcher.matchesNoneOf(s));
assertEquals(s.toString(), matcher.removeFrom(s));
assertEquals(s.toString(), matcher.replaceFrom(s, 'z'));
assertEquals(s.toString(), matcher.replaceFrom(s, "ZZ"));
assertEquals(s.toString(), matcher.trimFrom(s));
assertEquals(0, matcher.countIn(s));
}
private void reallyTestAllMatches(CharMatcher matcher, CharSequence s) {
assertTrue(matcher.matches(s.charAt(0)));
assertEquals(0, matcher.indexIn(s));
assertEquals(0, matcher.indexIn(s, 0));
assertEquals(1, matcher.indexIn(s, 1));
assertEquals(-1, matcher.indexIn(s, s.length()));
assertEquals(s.length() - 1, matcher.lastIndexIn(s));
assertTrue(matcher.matchesAnyOf(s));
assertTrue(matcher.matchesAllOf(s));
assertFalse(matcher.matchesNoneOf(s));
assertEquals("", matcher.removeFrom(s));
assertEquals(Strings.repeat("z", s.length()), matcher.replaceFrom(s, 'z'));
assertEquals(Strings.repeat("ZZ", s.length()), matcher.replaceFrom(s, "ZZ"));
assertEquals("", matcher.trimFrom(s));
assertEquals(s.length(), matcher.countIn(s));
}
public void testGeneral() {
doTestGeneral(is('a'), 'a', 'b');
doTestGeneral(isNot('a'), 'b', 'a');
doTestGeneral(anyOf("x"), 'x', 'z');
doTestGeneral(anyOf("xy"), 'y', 'z');
doTestGeneral(anyOf("CharMatcher"), 'C', 'z');
doTestGeneral(noneOf("CharMatcher"), 'z', 'C');
doTestGeneral(inRange('p', 'x'), 'q', 'z');
}
private void doTestGeneral(CharMatcher matcher, char match, char noMatch) {
doTestOneCharMatch(matcher, "" + match);
doTestOneCharNoMatch(matcher, "" + noMatch);
doTestMatchThenNoMatch(matcher, "" + match + noMatch);
doTestNoMatchThenMatch(matcher, "" + noMatch + match);
}
private void doTestOneCharMatch(CharMatcher matcher, String s) {
reallyTestOneCharMatch(matcher, s);
reallyTestOneCharNoMatch(matcher.negate(), s);
reallyTestOneCharMatch(matcher.precomputed(), s);
reallyTestOneCharNoMatch(matcher.negate().precomputed(), s);
reallyTestOneCharNoMatch(matcher.precomputed().negate(), s);
}
private void doTestOneCharNoMatch(CharMatcher matcher, String s) {
reallyTestOneCharNoMatch(matcher, s);
reallyTestOneCharMatch(matcher.negate(), s);
reallyTestOneCharNoMatch(matcher.precomputed(), s);
reallyTestOneCharMatch(matcher.negate().precomputed(), s);
reallyTestOneCharMatch(matcher.precomputed().negate(), s);
}
private void doTestMatchThenNoMatch(CharMatcher matcher, String s) {
reallyTestMatchThenNoMatch(matcher, s);
reallyTestNoMatchThenMatch(matcher.negate(), s);
reallyTestMatchThenNoMatch(matcher.precomputed(), s);
reallyTestNoMatchThenMatch(matcher.negate().precomputed(), s);
reallyTestNoMatchThenMatch(matcher.precomputed().negate(), s);
}
private void doTestNoMatchThenMatch(CharMatcher matcher, String s) {
reallyTestNoMatchThenMatch(matcher, s);
reallyTestMatchThenNoMatch(matcher.negate(), s);
reallyTestNoMatchThenMatch(matcher.precomputed(), s);
reallyTestMatchThenNoMatch(matcher.negate().precomputed(), s);
reallyTestMatchThenNoMatch(matcher.precomputed().negate(), s);
}
@SuppressWarnings("deprecation") // intentionally testing apply() method
private void reallyTestOneCharMatch(CharMatcher matcher, String s) {
assertTrue(matcher.matches(s.charAt(0)));
assertTrue(matcher.apply(s.charAt(0)));
assertEquals(0, matcher.indexIn(s));
assertEquals(0, matcher.indexIn(s, 0));
assertEquals(-1, matcher.indexIn(s, 1));
assertEquals(0, matcher.lastIndexIn(s));
assertTrue(matcher.matchesAnyOf(s));
assertTrue(matcher.matchesAllOf(s));
assertFalse(matcher.matchesNoneOf(s));
assertEquals("", matcher.removeFrom(s));
assertEquals("z", matcher.replaceFrom(s, 'z'));
assertEquals("ZZ", matcher.replaceFrom(s, "ZZ"));
assertEquals("", matcher.trimFrom(s));
assertEquals(1, matcher.countIn(s));
}
@SuppressWarnings("deprecation") // intentionally testing apply() method
private void reallyTestOneCharNoMatch(CharMatcher matcher, String s) {
assertFalse(matcher.matches(s.charAt(0)));
assertFalse(matcher.apply(s.charAt(0)));
assertEquals(-1, matcher.indexIn(s));
assertEquals(-1, matcher.indexIn(s, 0));
assertEquals(-1, matcher.indexIn(s, 1));
assertEquals(-1, matcher.lastIndexIn(s));
assertFalse(matcher.matchesAnyOf(s));
assertFalse(matcher.matchesAllOf(s));
assertTrue(matcher.matchesNoneOf(s));
assertSame(s, matcher.removeFrom(s));
assertSame(s, matcher.replaceFrom(s, 'z'));
assertSame(s, matcher.replaceFrom(s, "ZZ"));
assertSame(s, matcher.trimFrom(s));
assertSame(0, matcher.countIn(s));
}
private void reallyTestMatchThenNoMatch(CharMatcher matcher, String s) {
assertEquals(0, matcher.indexIn(s));
assertEquals(0, matcher.indexIn(s, 0));
assertEquals(-1, matcher.indexIn(s, 1));
assertEquals(-1, matcher.indexIn(s, 2));
assertEquals(0, matcher.lastIndexIn(s));
assertTrue(matcher.matchesAnyOf(s));
assertFalse(matcher.matchesAllOf(s));
assertFalse(matcher.matchesNoneOf(s));
assertEquals(s.substring(1), matcher.removeFrom(s));
assertEquals("z" + s.substring(1), matcher.replaceFrom(s, 'z'));
assertEquals("ZZ" + s.substring(1), matcher.replaceFrom(s, "ZZ"));
assertEquals(s.substring(1), matcher.trimFrom(s));
assertEquals(1, matcher.countIn(s));
}
private void reallyTestNoMatchThenMatch(CharMatcher matcher, String s) {
assertEquals(1, matcher.indexIn(s));
assertEquals(1, matcher.indexIn(s, 0));
assertEquals(1, matcher.indexIn(s, 1));
assertEquals(-1, matcher.indexIn(s, 2));
assertEquals(1, matcher.lastIndexIn(s));
assertTrue(matcher.matchesAnyOf(s));
assertFalse(matcher.matchesAllOf(s));
assertFalse(matcher.matchesNoneOf(s));
assertEquals(s.substring(0, 1), matcher.removeFrom(s));
assertEquals(s.substring(0, 1) + "z", matcher.replaceFrom(s, 'z'));
assertEquals(s.substring(0, 1) + "ZZ", matcher.replaceFrom(s, "ZZ"));
assertEquals(s.substring(0, 1), matcher.trimFrom(s));
assertEquals(1, matcher.countIn(s));
}
/**
* Checks that expected is equals to out, and further, if in is equals to expected, then out is
* successfully optimized to be identical to in, i.e. that "in" is simply returned.
*/
private void assertEqualsSame(String expected, String in, String out) {
if (expected.equals(in)) {
assertSame(in, out);
} else {
assertEquals(expected, out);
}
}
// Test collapse() a little differently than the rest, as we really want to
// cover lots of different configurations of input text
public void testCollapse() {
// collapsing groups of '-' into '_' or '-'
doTestCollapse("-", "_");
doTestCollapse("x-", "x_");
doTestCollapse("-x", "_x");
doTestCollapse("--", "_");
doTestCollapse("x--", "x_");
doTestCollapse("--x", "_x");
doTestCollapse("-x-", "_x_");
doTestCollapse("x-x", "x_x");
doTestCollapse("---", "_");
doTestCollapse("--x-", "_x_");
doTestCollapse("--xx", "_xx");
doTestCollapse("-x--", "_x_");
doTestCollapse("-x-x", "_x_x");
doTestCollapse("-xx-", "_xx_");
doTestCollapse("x--x", "x_x");
doTestCollapse("x-x-", "x_x_");
doTestCollapse("x-xx", "x_xx");
doTestCollapse("x-x--xx---x----x", "x_x_xx_x_x");
doTestCollapseWithNoChange("");
doTestCollapseWithNoChange("x");
doTestCollapseWithNoChange("xx");
}
private void doTestCollapse(String in, String out) {
// Try a few different matchers which all match '-' and not 'x'
// Try replacement chars that both do and do not change the value.
for (char replacement : new char[]{'_', '-'}) {
String expected = out.replace('_', replacement);
assertEqualsSame(expected, in, is('-').collapseFrom(in, replacement));
assertEqualsSame(expected, in, is('-').collapseFrom(in, replacement));
assertEqualsSame(expected, in, is('-').or(is('#')).collapseFrom(in, replacement));
assertEqualsSame(expected, in, isNot('x').collapseFrom(in, replacement));
assertEqualsSame(expected, in, is('x').negate().collapseFrom(in, replacement));
assertEqualsSame(expected, in, anyOf("-").collapseFrom(in, replacement));
assertEqualsSame(expected, in, anyOf("-#").collapseFrom(in, replacement));
assertEqualsSame(expected, in, anyOf("-#123").collapseFrom(in, replacement));
}
}
private void doTestCollapseWithNoChange(String inout) {
assertSame(inout, is('-').collapseFrom(inout, '_'));
assertSame(inout, is('-').or(is('#')).collapseFrom(inout, '_'));
assertSame(inout, isNot('x').collapseFrom(inout, '_'));
assertSame(inout, is('x').negate().collapseFrom(inout, '_'));
assertSame(inout, anyOf("-").collapseFrom(inout, '_'));
assertSame(inout, anyOf("-#").collapseFrom(inout, '_'));
assertSame(inout, anyOf("-#123").collapseFrom(inout, '_'));
assertSame(inout, CharMatcher.none().collapseFrom(inout, '_'));
}
public void testCollapse_any() {
assertEquals("", CharMatcher.any().collapseFrom("", '_'));
assertEquals("_", CharMatcher.any().collapseFrom("a", '_'));
assertEquals("_", CharMatcher.any().collapseFrom("ab", '_'));
assertEquals("_", CharMatcher.any().collapseFrom("abcd", '_'));
}
public void testTrimFrom() {
// trimming -
doTestTrimFrom("-", "");
doTestTrimFrom("x-", "x");
doTestTrimFrom("-x", "x");
doTestTrimFrom("--", "");
doTestTrimFrom("x--", "x");
doTestTrimFrom("--x", "x");
doTestTrimFrom("-x-", "x");
doTestTrimFrom("x-x", "x-x");
doTestTrimFrom("---", "");
doTestTrimFrom("--x-", "x");
doTestTrimFrom("--xx", "xx");
doTestTrimFrom("-x--", "x");
doTestTrimFrom("-x-x", "x-x");
doTestTrimFrom("-xx-", "xx");
doTestTrimFrom("x--x", "x--x");
doTestTrimFrom("x-x-", "x-x");
doTestTrimFrom("x-xx", "x-xx");
doTestTrimFrom("x-x--xx---x----x", "x-x--xx---x----x");
// additional testing using the doc example
assertEquals("cat", anyOf("ab").trimFrom("abacatbab"));
}
private void doTestTrimFrom(String in, String out) {
// Try a few different matchers which all match '-' and not 'x'
assertEquals(out, is('-').trimFrom(in));
assertEquals(out, is('-').or(is('#')).trimFrom(in));
assertEquals(out, isNot('x').trimFrom(in));
assertEquals(out, is('x').negate().trimFrom(in));
assertEquals(out, anyOf("-").trimFrom(in));
assertEquals(out, anyOf("-#").trimFrom(in));
assertEquals(out, anyOf("-#123").trimFrom(in));
}
public void testTrimLeadingFrom() {
// trimming -
doTestTrimLeadingFrom("-", "");
doTestTrimLeadingFrom("x-", "x-");
doTestTrimLeadingFrom("-x", "x");
doTestTrimLeadingFrom("--", "");
doTestTrimLeadingFrom("x--", "x--");
doTestTrimLeadingFrom("--x", "x");
doTestTrimLeadingFrom("-x-", "x-");
doTestTrimLeadingFrom("x-x", "x-x");
doTestTrimLeadingFrom("---", "");
doTestTrimLeadingFrom("--x-", "x-");
doTestTrimLeadingFrom("--xx", "xx");
doTestTrimLeadingFrom("-x--", "x--");
doTestTrimLeadingFrom("-x-x", "x-x");
doTestTrimLeadingFrom("-xx-", "xx-");
doTestTrimLeadingFrom("x--x", "x--x");
doTestTrimLeadingFrom("x-x-", "x-x-");
doTestTrimLeadingFrom("x-xx", "x-xx");
doTestTrimLeadingFrom("x-x--xx---x----x", "x-x--xx---x----x");
// additional testing using the doc example
assertEquals("catbab", anyOf("ab").trimLeadingFrom("abacatbab"));
}
private void doTestTrimLeadingFrom(String in, String out) {
// Try a few different matchers which all match '-' and not 'x'
assertEquals(out, is('-').trimLeadingFrom(in));
assertEquals(out, is('-').or(is('#')).trimLeadingFrom(in));
assertEquals(out, isNot('x').trimLeadingFrom(in));
assertEquals(out, is('x').negate().trimLeadingFrom(in));
assertEquals(out, anyOf("-#").trimLeadingFrom(in));
assertEquals(out, anyOf("-#123").trimLeadingFrom(in));
}
public void testTrimTrailingFrom() {
// trimming -
doTestTrimTrailingFrom("-", "");
doTestTrimTrailingFrom("x-", "x");
doTestTrimTrailingFrom("-x", "-x");
doTestTrimTrailingFrom("--", "");
doTestTrimTrailingFrom("x--", "x");
doTestTrimTrailingFrom("--x", "--x");
doTestTrimTrailingFrom("-x-", "-x");
doTestTrimTrailingFrom("x-x", "x-x");
doTestTrimTrailingFrom("---", "");
doTestTrimTrailingFrom("--x-", "--x");
doTestTrimTrailingFrom("--xx", "--xx");
doTestTrimTrailingFrom("-x--", "-x");
doTestTrimTrailingFrom("-x-x", "-x-x");
doTestTrimTrailingFrom("-xx-", "-xx");
doTestTrimTrailingFrom("x--x", "x--x");
doTestTrimTrailingFrom("x-x-", "x-x");
doTestTrimTrailingFrom("x-xx", "x-xx");
doTestTrimTrailingFrom("x-x--xx---x----x", "x-x--xx---x----x");
// additional testing using the doc example
assertEquals("abacat", anyOf("ab").trimTrailingFrom("abacatbab"));
}
private void doTestTrimTrailingFrom(String in, String out) {
// Try a few different matchers which all match '-' and not 'x'
assertEquals(out, is('-').trimTrailingFrom(in));
assertEquals(out, is('-').or(is('#')).trimTrailingFrom(in));
assertEquals(out, isNot('x').trimTrailingFrom(in));
assertEquals(out, is('x').negate().trimTrailingFrom(in));
assertEquals(out, anyOf("-#").trimTrailingFrom(in));
assertEquals(out, anyOf("-#123").trimTrailingFrom(in));
}
public void testTrimAndCollapse() {
// collapsing groups of '-' into '_' or '-'
doTestTrimAndCollapse("", "");
doTestTrimAndCollapse("x", "x");
doTestTrimAndCollapse("-", "");
doTestTrimAndCollapse("x-", "x");
doTestTrimAndCollapse("-x", "x");
doTestTrimAndCollapse("--", "");
doTestTrimAndCollapse("x--", "x");
doTestTrimAndCollapse("--x", "x");
doTestTrimAndCollapse("-x-", "x");
doTestTrimAndCollapse("x-x", "x_x");
doTestTrimAndCollapse("---", "");
doTestTrimAndCollapse("--x-", "x");
doTestTrimAndCollapse("--xx", "xx");
doTestTrimAndCollapse("-x--", "x");
doTestTrimAndCollapse("-x-x", "x_x");
doTestTrimAndCollapse("-xx-", "xx");
doTestTrimAndCollapse("x--x", "x_x");
doTestTrimAndCollapse("x-x-", "x_x");
doTestTrimAndCollapse("x-xx", "x_xx");
doTestTrimAndCollapse("x-x--xx---x----x", "x_x_xx_x_x");
}
private void doTestTrimAndCollapse(String in, String out) {
// Try a few different matchers which all match '-' and not 'x'
for (char replacement : new char[]{'_', '-'}) {
String expected = out.replace('_', replacement);
assertEqualsSame(expected, in, is('-').trimAndCollapseFrom(in, replacement));
assertEqualsSame(expected, in, is('-').or(is('#')).trimAndCollapseFrom(in, replacement));
assertEqualsSame(expected, in, isNot('x').trimAndCollapseFrom(in, replacement));
assertEqualsSame(expected, in, is('x').negate().trimAndCollapseFrom(in, replacement));
assertEqualsSame(expected, in, anyOf("-").trimAndCollapseFrom(in, replacement));
assertEqualsSame(expected, in, anyOf("-#").trimAndCollapseFrom(in, replacement));
assertEqualsSame(expected, in, anyOf("-#123").trimAndCollapseFrom(in, replacement));
}
}
public void testReplaceFrom() {
assertEquals("yoho", is('a').replaceFrom("yaha", 'o'));
assertEquals("yh", is('a').replaceFrom("yaha", ""));
assertEquals("yoho", is('a').replaceFrom("yaha", "o"));
assertEquals("yoohoo", is('a').replaceFrom("yaha", "oo"));
assertEquals("12 > 5", is('>').replaceFrom("12 > 5", ">"));
}
public void testPrecomputedOptimizations() {
// These are testing behavior that's never promised by the API.
// Some matchers are so efficient that it is a waste of effort to
// build a precomputed version.
CharMatcher m1 = is('x');
assertSame(m1, m1.precomputed());
assertEquals(m1.toString(), m1.precomputed().toString());
CharMatcher m2 = anyOf("Az");
assertSame(m2, m2.precomputed());
assertEquals(m2.toString(), m2.precomputed().toString());
CharMatcher m3 = inRange('A', 'Z');
assertSame(m3, m3.precomputed());
assertEquals(m3.toString(), m3.precomputed().toString());
assertSame(CharMatcher.none(), CharMatcher.none().precomputed());
assertSame(CharMatcher.any(), CharMatcher.any().precomputed());
}
public void testToString() {
assertToStringWorks("CharMatcher.none()", anyOf(""));
assertToStringWorks("CharMatcher.is('\\u0031')", anyOf("1"));
assertToStringWorks("CharMatcher.isNot('\\u0031')", isNot('1'));
assertToStringWorks("CharMatcher.anyOf(\"\\u0031\\u0032\")", anyOf("12"));
assertToStringWorks("CharMatcher.anyOf(\"\\u0031\\u0032\\u0033\")", anyOf("321"));
assertToStringWorks("CharMatcher.inRange('\\u0031', '\\u0033')", CharMatcher.inRange('1', '3'));
}
private static void assertToStringWorks(String expected, CharMatcher matcher) {
assertEquals(expected, matcher.toString());
assertEquals(expected, matcher.precomputed().toString());
assertEquals(expected, matcher.negate().negate().toString());
assertEquals(expected, matcher.negate().precomputed().negate().toString());
assertEquals(expected, matcher.negate().precomputed().negate().precomputed().toString());
}
}
4.Charsets字符集
不要这样做:
try {
bytes = string.getBytes("UTF-8");
} catch (UnsupportedEncodingException e) {
// how can this possibly happen?
throw new AssertionError(e);
}
而是这样做:
bytes = string.getBytes(Charsets.UTF_8);
Charsets
提供了对六个标准Charset
实现的常量引用,所有Java平台实现均支持。使用它们而不是通过名称来引用字符集。
(注意:如果使用的是JDK7,则应使用StandardCharsets
中的常量。)
4.1使用示例
import com.google.common.annotations.GwtIncompatible;
import com.google.common.base.Charsets;
import junit.framework.TestCase;
import java.nio.charset.Charset;
import java.util.Arrays;
public class CharsetsTest extends TestCase {
@GwtIncompatible // Non-UTF-8 Charset
public void testUsAscii() {
assertEquals(Charset.forName("US-ASCII"), Charsets.US_ASCII);
}
@GwtIncompatible // Non-UTF-8 Charset
public void testIso88591() {
assertEquals(Charset.forName("ISO-8859-1"), Charsets.ISO_8859_1);
}
public void testUtf8() {
assertEquals(Charset.forName("UTF-8"), Charsets.UTF_8);
}
@GwtIncompatible // Non-UTF-8 Charset
public void testUtf16be() {
assertEquals(Charset.forName("UTF-16BE"), Charsets.UTF_16BE);
}
@GwtIncompatible // Non-UTF-8 Charset
public void testUtf16le() {
assertEquals(Charset.forName("UTF-16LE"), Charsets.UTF_16LE);
}
@GwtIncompatible // Non-UTF-8 Charset
public void testUtf16() {
assertEquals(Charset.forName("UTF-16"), Charsets.UTF_16);
}
@GwtIncompatible // Non-UTF-8 Charset
public void testWhyUsAsciiIsDangerous() {
byte[] b1 = "朝日新聞".getBytes(Charsets.US_ASCII);
byte[] b2 = "聞朝日新".getBytes(Charsets.US_ASCII);
byte[] b3 = "????".getBytes(Charsets.US_ASCII);
byte[] b4 = "ニュース".getBytes(Charsets.US_ASCII);
byte[] b5 = "スューー".getBytes(Charsets.US_ASCII);
// Assert they are all equal (using the transitive property)
assertTrue(Arrays.equals(b1, b2));
assertTrue(Arrays.equals(b2, b3));
assertTrue(Arrays.equals(b3, b4));
assertTrue(Arrays.equals(b4, b5));
}
}
5.Joiner连接器
用分隔符将字符串序列连接在一起可能会很棘手——但事实并非如此。如果你的序列包含null,则可能会更加困难。Joiner的流利风格使其变得简单。
Joiner joiner = Joiner.on("; ").skipNulls();
return joiner.join("Harry", null, "Ron", "Hermione");
返回字符串"Harry; Ron; Hermione"。或者,可以使用useForNull(String)
指定要使用的字符串代替null,而不是使用skipNulls
忽略null。
也可以在对象上使用Joiner
,这些对象将使用其toString()
进行转换,然后再进行连接。
Joiner.on(",").join(Arrays.asList(1, 5, 7)); // returns "1,5,7"
警告: 连接器实例始终是不可变的。连接器配置方法始终返回一个新的Joiner
连接器,必须使用它来获取所需的语义。这使任何Joiner
都是线程安全的,并可用作static final
静态最终常量。
5.1使用示例
import com.google.common.annotations.GwtIncompatible;
import com.google.common.base.Joiner;
import com.google.common.base.Joiner.MapJoiner;
import com.google.common.collect.*;
import com.google.common.testing.NullPointerTester;
import junit.framework.AssertionFailedError;
import junit.framework.TestCase;
import java.io.IOException;
import java.util.Arrays;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
public class JoinerTest extends TestCase {
private static final Joiner J = Joiner.on("-");
// <Integer> needed to prevent warning :(
private static final Iterable<Integer> ITERABLE_ = Arrays.<Integer>asList();
private static final Iterable<Integer> ITERABLE_1 = Arrays.asList(1);
private static final Iterable<Integer> ITERABLE_12 = Arrays.asList(1, 2);
private static final Iterable<Integer> ITERABLE_123 = Arrays.asList(1, 2, 3);
private static final Iterable<Integer> ITERABLE_NULL = Arrays.asList((Integer) null);
private static final Iterable<Integer> ITERABLE_NULL_NULL = Arrays.asList((Integer) null, null);
private static final Iterable<Integer> ITERABLE_NULL_1 = Arrays.asList(null, 1);
private static final Iterable<Integer> ITERABLE_1_NULL = Arrays.asList(1, null);
private static final Iterable<Integer> ITERABLE_1_NULL_2 = Arrays.asList(1, null, 2);
private static final Iterable<Integer> ITERABLE_FOUR_NULLS =
Arrays.asList((Integer) null, null, null, null);
public void testNoSpecialNullBehavior() {
checkNoOutput(J, ITERABLE_);
checkResult(J, ITERABLE_1, "1");
checkResult(J, ITERABLE_12, "1-2");
checkResult(J, ITERABLE_123, "1-2-3");
try {
J.join(ITERABLE_NULL);
fail();
} catch (NullPointerException expected) {
}
try {
J.join(ITERABLE_1_NULL_2);
fail();
} catch (NullPointerException expected) {
}
try {
J.join(ITERABLE_NULL.iterator());
fail();
} catch (NullPointerException expected) {
}
try {
J.join(ITERABLE_1_NULL_2.iterator());
fail();
} catch (NullPointerException expected) {
}
}
public void testOnCharOverride() {
Joiner onChar = Joiner.on('-');
checkNoOutput(onChar, ITERABLE_);
checkResult(onChar, ITERABLE_1, "1");
checkResult(onChar, ITERABLE_12, "1-2");
checkResult(onChar, ITERABLE_123, "1-2-3");
}
public void testSkipNulls() {
Joiner skipNulls = J.skipNulls();
checkNoOutput(skipNulls, ITERABLE_);
checkNoOutput(skipNulls, ITERABLE_NULL);
checkNoOutput(skipNulls, ITERABLE_NULL_NULL);
checkNoOutput(skipNulls, ITERABLE_FOUR_NULLS);
checkResult(skipNulls, ITERABLE_1, "1");
checkResult(skipNulls, ITERABLE_12, "1-2");
checkResult(skipNulls, ITERABLE_123, "1-2-3");
checkResult(skipNulls, ITERABLE_NULL_1, "1");
checkResult(skipNulls, ITERABLE_1_NULL, "1");
checkResult(skipNulls, ITERABLE_1_NULL_2, "1-2");
}
public void testUseForNull() {
Joiner zeroForNull = J.useForNull("0");
checkNoOutput(zeroForNull, ITERABLE_);
checkResult(zeroForNull, ITERABLE_1, "1");
checkResult(zeroForNull, ITERABLE_12, "1-2");
checkResult(zeroForNull, ITERABLE_123, "1-2-3");
checkResult(zeroForNull, ITERABLE_NULL, "0");
checkResult(zeroForNull, ITERABLE_NULL_NULL, "0-0");
checkResult(zeroForNull, ITERABLE_NULL_1, "0-1");
checkResult(zeroForNull, ITERABLE_1_NULL, "1-0");
checkResult(zeroForNull, ITERABLE_1_NULL_2, "1-0-2");
checkResult(zeroForNull, ITERABLE_FOUR_NULLS, "0-0-0-0");
}
private static void checkNoOutput(Joiner joiner, Iterable<Integer> set) {
assertEquals("", joiner.join(set));
assertEquals("", joiner.join(set.iterator()));
Object[] array = Lists.newArrayList(set).toArray(new Integer[0]);
assertEquals("", joiner.join(array));
StringBuilder sb1FromIterable = new StringBuilder();
assertSame(sb1FromIterable, joiner.appendTo(sb1FromIterable, set));
assertEquals(0, sb1FromIterable.length());
StringBuilder sb1FromIterator = new StringBuilder();
assertSame(sb1FromIterator, joiner.appendTo(sb1FromIterator, set));
assertEquals(0, sb1FromIterator.length());
StringBuilder sb2 = new StringBuilder();
assertSame(sb2, joiner.appendTo(sb2, array));
assertEquals(0, sb2.length());
try {
joiner.appendTo(NASTY_APPENDABLE, set);
} catch (IOException e) {
throw new AssertionError(e);
}
try {
joiner.appendTo(NASTY_APPENDABLE, set.iterator());
} catch (IOException e) {
throw new AssertionError(e);
}
try {
joiner.appendTo(NASTY_APPENDABLE, array);
} catch (IOException e) {
throw new AssertionError(e);
}
}
private static final Appendable NASTY_APPENDABLE =
new Appendable() {
@Override
public Appendable append(CharSequence csq) throws IOException {
throw new IOException();
}
@Override
public Appendable append(CharSequence csq, int start, int end) throws IOException {
throw new IOException();
}
@Override
public Appendable append(char c) throws IOException {
throw new IOException();
}
};
private static void checkResult(Joiner joiner, Iterable<Integer> parts, String expected) {
assertEquals(expected, joiner.join(parts));
assertEquals(expected, joiner.join(parts.iterator()));
StringBuilder sb1FromIterable = new StringBuilder().append('x');
joiner.appendTo(sb1FromIterable, parts);
assertEquals("x" + expected, sb1FromIterable.toString());
StringBuilder sb1FromIterator = new StringBuilder().append('x');
joiner.appendTo(sb1FromIterator, parts.iterator());
assertEquals("x" + expected, sb1FromIterator.toString());
Integer[] partsArray = Lists.newArrayList(parts).toArray(new Integer[0]);
assertEquals(expected, joiner.join(partsArray));
StringBuilder sb2 = new StringBuilder().append('x');
joiner.appendTo(sb2, partsArray);
assertEquals("x" + expected, sb2.toString());
int num = partsArray.length - 2;
if (num >= 0) {
Object[] rest = new Integer[num];
for (int i = 0; i < num; i++) {
rest[i] = partsArray[i + 2];
}
assertEquals(expected, joiner.join(partsArray[0], partsArray[1], rest));
StringBuilder sb3 = new StringBuilder().append('x');
joiner.appendTo(sb3, partsArray[0], partsArray[1], rest);
assertEquals("x" + expected, sb3.toString());
}
}
public void test_useForNull_skipNulls() {
Joiner j = Joiner.on("x").useForNull("y");
try {
j = j.skipNulls();
fail();
} catch (UnsupportedOperationException expected) {
}
}
public void test_skipNulls_useForNull() {
Joiner j = Joiner.on("x").skipNulls();
try {
j = j.useForNull("y");
fail();
} catch (UnsupportedOperationException expected) {
}
}
public void test_useForNull_twice() {
Joiner j = Joiner.on("x").useForNull("y");
try {
j = j.useForNull("y");
fail();
} catch (UnsupportedOperationException expected) {
}
}
public void testMap() {
MapJoiner j = Joiner.on(';').withKeyValueSeparator(':');
assertEquals("", j.join(ImmutableMap.of()));
assertEquals(":", j.join(ImmutableMap.of("", "")));
Map<String, String> mapWithNulls = Maps.newLinkedHashMap();
mapWithNulls.put("a", null);
mapWithNulls.put(null, "b");
try {
j.join(mapWithNulls);
fail();
} catch (NullPointerException expected) {
}
assertEquals("a:00;00:b", j.useForNull("00").join(mapWithNulls));
StringBuilder sb = new StringBuilder();
j.appendTo(sb, ImmutableMap.of(1, 2, 3, 4, 5, 6));
assertEquals("1:2;3:4;5:6", sb.toString());
}
public void testEntries() {
MapJoiner j = Joiner.on(";").withKeyValueSeparator(":");
assertEquals("", j.join(ImmutableMultimap.of().entries()));
assertEquals("", j.join(ImmutableMultimap.of().entries().iterator()));
assertEquals(":", j.join(ImmutableMultimap.of("", "").entries()));
assertEquals(":", j.join(ImmutableMultimap.of("", "").entries().iterator()));
assertEquals("1:a;1:b", j.join(ImmutableMultimap.of("1", "a", "1", "b").entries()));
assertEquals("1:a;1:b", j.join(ImmutableMultimap.of("1", "a", "1", "b").entries().iterator()));
Map<String, String> mapWithNulls = Maps.newLinkedHashMap();
mapWithNulls.put("a", null);
mapWithNulls.put(null, "b");
Set<Entry<String, String>> entriesWithNulls = mapWithNulls.entrySet();
try {
j.join(entriesWithNulls);
fail();
} catch (NullPointerException expected) {
}
try {
j.join(entriesWithNulls.iterator());
fail();
} catch (NullPointerException expected) {
}
assertEquals("a:00;00:b", j.useForNull("00").join(entriesWithNulls));
assertEquals("a:00;00:b", j.useForNull("00").join(entriesWithNulls.iterator()));
StringBuilder sb1 = new StringBuilder();
j.appendTo(sb1, ImmutableMultimap.of(1, 2, 3, 4, 5, 6, 1, 3, 5, 10).entries());
assertEquals("1:2;1:3;3:4;5:6;5:10", sb1.toString());
StringBuilder sb2 = new StringBuilder();
j.appendTo(sb2, ImmutableMultimap.of(1, 2, 3, 4, 5, 6, 1, 3, 5, 10).entries().iterator());
assertEquals("1:2;1:3;3:4;5:6;5:10", sb2.toString());
}
public void test_skipNulls_onMap() {
Joiner j = Joiner.on(",").skipNulls();
try {
j.withKeyValueSeparator("/");
fail();
} catch (UnsupportedOperationException expected) {
}
}
private static class DontStringMeBro implements CharSequence {
@Override
public int length() {
return 3;
}
@Override
public char charAt(int index) {
return "foo".charAt(index);
}
@Override
public CharSequence subSequence(int start, int end) {
return "foo".subSequence(start, end);
}
@Override
public String toString() {
throw new AssertionFailedError("shouldn't be invoked");
}
}
// Don't do this.
private static class IterableIterator implements Iterable<Integer>, Iterator<Integer> {
private static final ImmutableSet<Integer> INTEGERS = ImmutableSet.of(1, 2, 3, 4);
private final Iterator<Integer> iterator;
public IterableIterator() {
this.iterator = iterator();
}
@Override
public Iterator<Integer> iterator() {
return INTEGERS.iterator();
}
@Override
public boolean hasNext() {
return iterator.hasNext();
}
@Override
public Integer next() {
return iterator.next();
}
@Override
public void remove() {
iterator.remove();
}
}
@GwtIncompatible // StringBuilder.append in GWT invokes Object.toString(), unlike the JRE version.
public void testDontConvertCharSequenceToString() {
assertEquals("foo,foo", Joiner.on(",").join(new DontStringMeBro(), new DontStringMeBro()));
assertEquals(
"foo,bar,foo",
Joiner.on(",").useForNull("bar").join(new DontStringMeBro(), null, new DontStringMeBro()));
}
@GwtIncompatible // NullPointerTester
public void testNullPointers() {
NullPointerTester tester = new NullPointerTester();
tester.testAllPublicStaticMethods(Joiner.class);
tester.testInstanceMethods(Joiner.on(","), NullPointerTester.Visibility.PACKAGE);
tester.testInstanceMethods(Joiner.on(",").skipNulls(), NullPointerTester.Visibility.PACKAGE);
tester.testInstanceMethods(
Joiner.on(",").useForNull("x"), NullPointerTester.Visibility.PACKAGE);
tester.testInstanceMethods(
Joiner.on(",").withKeyValueSeparator("="), NullPointerTester.Visibility.PACKAGE);
}
}
6.Splitter拆分器
用于拆分字符串的内置Java工具具有一些古怪的行为。例如,String.split
会静默丢弃尾部的分隔符,而StringTokenizer
只考虑五个空格字符而不考虑其它字符。
测验:",a,,b,".split(",")
返回什么?
"", "a", "", "b", ""
null, "a", null, "b", null
"a", null, "b"
"a", "b"
- 不是上述任何一个
正确的答案不是上述任何一个
:"", "a", "", "b"
。只跳过尾部的空字符串。
Splitter
拆分器使用令人放心的直接流利的模式,可以完全控制所有这些令人困惑的行为。
Splitter.on(',')
.trimResults()
.omitEmptyStrings()
.split("foo,bar,, qux");
返回包含"foo", “bar”, "qux"的Iterable<String>
。Splitter
拆分器可以设置在任何Pattern
,char
,String
或CharMatcher
上拆分。
6.1基本工厂
方法 | 描述 | 示例 |
---|---|---|
Splitter.on(char) | 根据出现的特定单个字符进行拆分。 | Splitter.on(';') |
Splitter.on(CharMatcher) | 根据出现的某个类别中任意字符进行拆分。 | Splitter.on(CharMatcher.BREAKING_WHITESPACE)Splitter.on(CharMatcher.anyOf(";,.")) |
Splitter.on(String) | 在String字符串上分割。 | Splitter.on(",") |
Splitter.on(Pattern)Splitter.onPattern(String) | 按正则表达式拆分。 | Splitter.onPattern("\r?\n") |
Splitter.fixedLength(int) | 将字符串拆分为指定固定长度的子字符串。最后一项可以小于length长度,但永远不会为空。 | Splitter.fixedLength(3) |
6.2修饰符
方法 | 描述 | 示例 |
---|---|---|
omitEmptyStrings() | 自动从结果中删除空字符串。 | Splitter.on(',').omitEmptyStrings().split("a,,c,d")returns"a","c","d" |
trimResults() | 从结果中修剪空格;等效于trimResults(CharMatcher.WHITESPACE). | Splitter.on(',').trimResults().split("a,b,c,d")returns"a","b","c","d" |
trimResults(CharMatcher) | 从结果中修剪与指定CharMatcher匹配的字符。 | Splitter.on(',').trimResults(CharMatcher.is('')).split("a,b,c_")returns"a","b","c". |
limit(int) | 返回指定数量的字符串后停止拆分。 | Splitter.on(',').limit(3).split("a,b,c,d")returns"a","b","c,d" |
如果希望获取List
列表,请使用splitToList()
代替split()
。
警告: 拆分器实例始终是不可变的。拆分器配置方法将始终返回新的Splitter
拆分器,必须使用它来获取所需的语义。这样可以确保任何Splitter
线程安全,并可用作static final
静态最终常量。
6.3Map拆分器
还可以使用拆分器通过使用withKeyValueSeparator()
指定第二个分隔符对map进行反序列化。生成的MapSplitter
将使用拆分器的分隔符将输入拆分为条目,然后使用给定的键值分隔符将这些条目拆分为键和值,并返回Map<String, String>
。
6.4使用示例
import com.google.common.annotations.GwtIncompatible;
import com.google.common.base.CharMatcher;
import com.google.common.base.Splitter;
import com.google.common.base.Splitter.MapSplitter;
import com.google.common.collect.ImmutableMap;
import com.google.common.testing.NullPointerTester;
import junit.framework.TestCase;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.common.truth.Truth.assertThat;
public class SplitterTest extends TestCase {
private static final Splitter COMMA_SPLITTER = Splitter.on(',');
public void testSplitNullString() {
try {
COMMA_SPLITTER.split(null);
fail();
} catch (NullPointerException expected) {
}
}
public void testCharacterSimpleSplit() {
String simple = "a,b,c";
Iterable<String> letters = COMMA_SPLITTER.split(simple);
assertThat(letters).containsExactly("a", "b", "c").inOrder();
}
public void testCharacterSimpleSplitToList() {
String simple = "a,b,c";
List<String> letters = COMMA_SPLITTER.splitToList(simple);
assertThat(letters).containsExactly("a", "b", "c").inOrder();
}
public void testCharacterSimpleSplitToStream() {
String simple = "a,b,c";
List<String> letters = COMMA_SPLITTER.splitToStream(simple).collect(toImmutableList());
assertThat(letters).containsExactly("a", "b", "c").inOrder();
}
public void testToString() {
assertEquals("[]", COMMA_SPLITTER.split("").toString());
assertEquals("[a, b, c]", COMMA_SPLITTER.split("a,b,c").toString());
assertEquals("[yam, bam, jam, ham]", Splitter.on(", ").split("yam, bam, jam, ham").toString());
}
public void testCharacterSimpleSplitWithNoDelimiter() {
String simple = "a,b,c";
Iterable<String> letters = Splitter.on('.').split(simple);
assertThat(letters).containsExactly("a,b,c").inOrder();
}
public void testCharacterSplitWithDoubleDelimiter() {
String doubled = "a,,b,c";
Iterable<String> letters = COMMA_SPLITTER.split(doubled);
assertThat(letters).containsExactly("a", "", "b", "c").inOrder();
}
public void testCharacterSplitWithDoubleDelimiterAndSpace() {
String doubled = "a,, b,c";
Iterable<String> letters = COMMA_SPLITTER.split(doubled);
assertThat(letters).containsExactly("a", "", " b", "c").inOrder();
}
public void testCharacterSplitWithTrailingDelimiter() {
String trailing = "a,b,c,";
Iterable<String> letters = COMMA_SPLITTER.split(trailing);
assertThat(letters).containsExactly("a", "b", "c", "").inOrder();
}
public void testCharacterSplitWithLeadingDelimiter() {
String leading = ",a,b,c";
Iterable<String> letters = COMMA_SPLITTER.split(leading);
assertThat(letters).containsExactly("", "a", "b", "c").inOrder();
}
public void testCharacterSplitWithMultipleLetters() {
Iterable<String> testCharacteringMotto =
Splitter.on('-').split("Testing-rocks-Debugging-sucks");
assertThat(testCharacteringMotto)
.containsExactly("Testing", "rocks", "Debugging", "sucks")
.inOrder();
}
public void testCharacterSplitWithMatcherDelimiter() {
Iterable<String> testCharacteringMotto =
Splitter.on(CharMatcher.whitespace()).split("Testing\nrocks\tDebugging sucks");
assertThat(testCharacteringMotto)
.containsExactly("Testing", "rocks", "Debugging", "sucks")
.inOrder();
}
public void testCharacterSplitWithDoubleDelimiterOmitEmptyStrings() {
String doubled = "a..b.c";
Iterable<String> letters = Splitter.on('.').omitEmptyStrings().split(doubled);
assertThat(letters).containsExactly("a", "b", "c").inOrder();
}
public void testCharacterSplitEmptyToken() {
String emptyToken = "a. .c";
Iterable<String> letters = Splitter.on('.').trimResults().split(emptyToken);
assertThat(letters).containsExactly("a", "", "c").inOrder();
}
public void testCharacterSplitEmptyTokenOmitEmptyStrings() {
String emptyToken = "a. .c";
Iterable<String> letters = Splitter.on('.').omitEmptyStrings().trimResults().split(emptyToken);
assertThat(letters).containsExactly("a", "c").inOrder();
}
public void testCharacterSplitOnEmptyString() {
Iterable<String> nothing = Splitter.on('.').split("");
assertThat(nothing).containsExactly("").inOrder();
}
public void testCharacterSplitOnEmptyStringOmitEmptyStrings() {
assertThat(Splitter.on('.').omitEmptyStrings().split("")).isEmpty();
}
public void testCharacterSplitOnOnlyDelimiter() {
Iterable<String> blankblank = Splitter.on('.').split(".");
assertThat(blankblank).containsExactly("", "").inOrder();
}
public void testCharacterSplitOnOnlyDelimitersOmitEmptyStrings() {
Iterable<String> empty = Splitter.on('.').omitEmptyStrings().split("...");
assertThat(empty).isEmpty();
}
public void testCharacterSplitWithTrim() {
String jacksons =
"arfo(Marlon)aorf, (Michael)orfa, afro(Jackie)orfa, " + "ofar(Jemaine), aff(Tito)";
Iterable<String> family =
COMMA_SPLITTER
.trimResults(CharMatcher.anyOf("afro").or(CharMatcher.whitespace()))
.split(jacksons);
assertThat(family)
.containsExactly("(Marlon)", "(Michael)", "(Jackie)", "(Jemaine)", "(Tito)")
.inOrder();
}
public void testStringSimpleSplit() {
String simple = "a,b,c";
Iterable<String> letters = Splitter.on(",").split(simple);
assertThat(letters).containsExactly("a", "b", "c").inOrder();
}
public void testStringSimpleSplitWithNoDelimiter() {
String simple = "a,b,c";
Iterable<String> letters = Splitter.on(".").split(simple);
assertThat(letters).containsExactly("a,b,c").inOrder();
}
public void testStringSplitWithDoubleDelimiter() {
String doubled = "a,,b,c";
Iterable<String> letters = Splitter.on(",").split(doubled);
assertThat(letters).containsExactly("a", "", "b", "c").inOrder();
}
public void testStringSplitWithDoubleDelimiterAndSpace() {
String doubled = "a,, b,c";
Iterable<String> letters = Splitter.on(",").split(doubled);
assertThat(letters).containsExactly("a", "", " b", "c").inOrder();
}
public void testStringSplitWithTrailingDelimiter() {
String trailing = "a,b,c,";
Iterable<String> letters = Splitter.on(",").split(trailing);
assertThat(letters).containsExactly("a", "b", "c", "").inOrder();
}
public void testStringSplitWithLeadingDelimiter() {
String leading = ",a,b,c";
Iterable<String> letters = Splitter.on(",").split(leading);
assertThat(letters).containsExactly("", "a", "b", "c").inOrder();
}
public void testStringSplitWithMultipleLetters() {
Iterable<String> testStringingMotto = Splitter.on("-").split("Testing-rocks-Debugging-sucks");
assertThat(testStringingMotto)
.containsExactly("Testing", "rocks", "Debugging", "sucks")
.inOrder();
}
public void testStringSplitWithDoubleDelimiterOmitEmptyStrings() {
String doubled = "a..b.c";
Iterable<String> letters = Splitter.on(".").omitEmptyStrings().split(doubled);
assertThat(letters).containsExactly("a", "b", "c").inOrder();
}
public void testStringSplitEmptyToken() {
String emptyToken = "a. .c";
Iterable<String> letters = Splitter.on(".").trimResults().split(emptyToken);
assertThat(letters).containsExactly("a", "", "c").inOrder();
}
public void testStringSplitEmptyTokenOmitEmptyStrings() {
String emptyToken = "a. .c";
Iterable<String> letters = Splitter.on(".").omitEmptyStrings().trimResults().split(emptyToken);
assertThat(letters).containsExactly("a", "c").inOrder();
}
public void testStringSplitWithLongDelimiter() {
String longDelimiter = "a, b, c";
Iterable<String> letters = Splitter.on(", ").split(longDelimiter);
assertThat(letters).containsExactly("a", "b", "c").inOrder();
}
public void testStringSplitWithLongLeadingDelimiter() {
String longDelimiter = ", a, b, c";
Iterable<String> letters = Splitter.on(", ").split(longDelimiter);
assertThat(letters).containsExactly("", "a", "b", "c").inOrder();
}
public void testStringSplitWithLongTrailingDelimiter() {
String longDelimiter = "a, b, c, ";
Iterable<String> letters = Splitter.on(", ").split(longDelimiter);
assertThat(letters).containsExactly("a", "b", "c", "").inOrder();
}
public void testStringSplitWithDelimiterSubstringInValue() {
String fourCommasAndFourSpaces = ",,,, ";
Iterable<String> threeCommasThenThreeSpaces = Splitter.on(", ").split(fourCommasAndFourSpaces);
assertThat(threeCommasThenThreeSpaces).containsExactly(",,,", " ").inOrder();
}
public void testStringSplitWithEmptyString() {
try {
Splitter.on("");
fail();
} catch (IllegalArgumentException expected) {
}
}
public void testStringSplitOnEmptyString() {
Iterable<String> notMuch = Splitter.on(".").split("");
assertThat(notMuch).containsExactly("").inOrder();
}
public void testStringSplitOnEmptyStringOmitEmptyString() {
assertThat(Splitter.on(".").omitEmptyStrings().split("")).isEmpty();
}
public void testStringSplitOnOnlyDelimiter() {
Iterable<String> blankblank = Splitter.on(".").split(".");
assertThat(blankblank).containsExactly("", "").inOrder();
}
public void testStringSplitOnOnlyDelimitersOmitEmptyStrings() {
Iterable<String> empty = Splitter.on(".").omitEmptyStrings().split("...");
assertThat(empty).isEmpty();
}
public void testStringSplitWithTrim() {
String jacksons =
"arfo(Marlon)aorf, (Michael)orfa, afro(Jackie)orfa, " + "ofar(Jemaine), aff(Tito)";
Iterable<String> family =
Splitter.on(",")
.trimResults(CharMatcher.anyOf("afro").or(CharMatcher.whitespace()))
.split(jacksons);
assertThat(family)
.containsExactly("(Marlon)", "(Michael)", "(Jackie)", "(Jemaine)", "(Tito)")
.inOrder();
}
@GwtIncompatible // Splitter.onPattern
public void testPatternSimpleSplit() {
String simple = "a,b,c";
Iterable<String> letters = Splitter.onPattern(",").split(simple);
assertThat(letters).containsExactly("a", "b", "c").inOrder();
}
@GwtIncompatible // Splitter.onPattern
public void testPatternSimpleSplitWithNoDelimiter() {
String simple = "a,b,c";
Iterable<String> letters = Splitter.onPattern("foo").split(simple);
assertThat(letters).containsExactly("a,b,c").inOrder();
}
@GwtIncompatible // Splitter.onPattern
public void testPatternSplitWithDoubleDelimiter() {
String doubled = "a,,b,c";
Iterable<String> letters = Splitter.onPattern(",").split(doubled);
assertThat(letters).containsExactly("a", "", "b", "c").inOrder();
}
@GwtIncompatible // Splitter.onPattern
public void testPatternSplitWithDoubleDelimiterAndSpace() {
String doubled = "a,, b,c";
Iterable<String> letters = Splitter.onPattern(",").split(doubled);
assertThat(letters).containsExactly("a", "", " b", "c").inOrder();
}
@GwtIncompatible // Splitter.onPattern
public void testPatternSplitWithTrailingDelimiter() {
String trailing = "a,b,c,";
Iterable<String> letters = Splitter.onPattern(",").split(trailing);
assertThat(letters).containsExactly("a", "b", "c", "").inOrder();
}
@GwtIncompatible // Splitter.onPattern
public void testPatternSplitWithLeadingDelimiter() {
String leading = ",a,b,c";
Iterable<String> letters = Splitter.onPattern(",").split(leading);
assertThat(letters).containsExactly("", "a", "b", "c").inOrder();
}
@GwtIncompatible // Splitter.onPattern
public void testPatternSplitWithMultipleLetters() {
Iterable<String> testPatterningMotto =
Splitter.onPattern("-").split("Testing-rocks-Debugging-sucks");
assertThat(testPatterningMotto)
.containsExactly("Testing", "rocks", "Debugging", "sucks")
.inOrder();
}
@GwtIncompatible // java.util.regex.Pattern
private static Pattern literalDotPattern() {
return Pattern.compile("\\.");
}
@GwtIncompatible // java.util.regex.Pattern
public void testPatternSplitWithDoubleDelimiterOmitEmptyStrings() {
String doubled = "a..b.c";
Iterable<String> letters = Splitter.on(literalDotPattern()).omitEmptyStrings().split(doubled);
assertThat(letters).containsExactly("a", "b", "c").inOrder();
}
@GwtIncompatible // java.util.regex.Pattern
public void testPatternSplitWordBoundary() {
String string = "foo<bar>bletch";
Iterable<String> words = Splitter.on(Pattern.compile("\\b")).split(string);
assertThat(words).containsExactly("foo", "<", "bar", ">", "bletch").inOrder();
}
@GwtIncompatible // java.util.regex.Pattern
public void testPatternSplitWordBoundary_singleCharInput() {
String string = "f";
Iterable<String> words = Splitter.on(Pattern.compile("\\b")).split(string);
assertThat(words).containsExactly("f").inOrder();
}
@GwtIncompatible // java.util.regex.Pattern
public void testPatternSplitWordBoundary_singleWordInput() {
String string = "foo";
Iterable<String> words = Splitter.on(Pattern.compile("\\b")).split(string);
assertThat(words).containsExactly("foo").inOrder();
}
@GwtIncompatible // java.util.regex.Pattern
public void testPatternSplitEmptyToken() {
String emptyToken = "a. .c";
Iterable<String> letters = Splitter.on(literalDotPattern()).trimResults().split(emptyToken);
assertThat(letters).containsExactly("a", "", "c").inOrder();
}
@GwtIncompatible // java.util.regex.Pattern
public void testPatternSplitEmptyTokenOmitEmptyStrings() {
String emptyToken = "a. .c";
Iterable<String> letters =
Splitter.on(literalDotPattern()).omitEmptyStrings().trimResults().split(emptyToken);
assertThat(letters).containsExactly("a", "c").inOrder();
}
@GwtIncompatible // java.util.regex.Pattern
public void testPatternSplitOnOnlyDelimiter() {
Iterable<String> blankblank = Splitter.on(literalDotPattern()).split(".");
assertThat(blankblank).containsExactly("", "").inOrder();
}
@GwtIncompatible // java.util.regex.Pattern
public void testPatternSplitOnOnlyDelimitersOmitEmptyStrings() {
Iterable<String> empty = Splitter.on(literalDotPattern()).omitEmptyStrings().split("...");
assertThat(empty).isEmpty();
}
@GwtIncompatible // java.util.regex.Pattern
public void testPatternSplitMatchingIsGreedy() {
String longDelimiter = "a, b, c";
Iterable<String> letters = Splitter.on(Pattern.compile(",\\s*")).split(longDelimiter);
assertThat(letters).containsExactly("a", "b", "c").inOrder();
}
@GwtIncompatible // java.util.regex.Pattern
public void testPatternSplitWithLongLeadingDelimiter() {
String longDelimiter = ", a, b, c";
Iterable<String> letters = Splitter.on(Pattern.compile(", ")).split(longDelimiter);
assertThat(letters).containsExactly("", "a", "b", "c").inOrder();
}
@GwtIncompatible // java.util.regex.Pattern
public void testPatternSplitWithLongTrailingDelimiter() {
String longDelimiter = "a, b, c/ ";
Iterable<String> letters = Splitter.on(Pattern.compile("[,/]\\s")).split(longDelimiter);
assertThat(letters).containsExactly("a", "b", "c", "").inOrder();
}
@GwtIncompatible // java.util.regex.Pattern
public void testPatternSplitInvalidPattern() {
try {
Splitter.on(Pattern.compile("a*"));
fail();
} catch (IllegalArgumentException expected) {
}
}
@GwtIncompatible // java.util.regex.Pattern
public void testPatternSplitWithTrim() {
String jacksons =
"arfo(Marlon)aorf, (Michael)orfa, afro(Jackie)orfa, " + "ofar(Jemaine), aff(Tito)";
Iterable<String> family =
Splitter.on(Pattern.compile(","))
.trimResults(CharMatcher.anyOf("afro").or(CharMatcher.whitespace()))
.split(jacksons);
assertThat(family)
.containsExactly("(Marlon)", "(Michael)", "(Jackie)", "(Jemaine)", "(Tito)")
.inOrder();
}
public void testSplitterIterableIsUnmodifiable_char() {
assertIteratorIsUnmodifiable(COMMA_SPLITTER.split("a,b").iterator());
}
public void testSplitterIterableIsUnmodifiable_string() {
assertIteratorIsUnmodifiable(Splitter.on(",").split("a,b").iterator());
}
@GwtIncompatible // java.util.regex.Pattern
public void testSplitterIterableIsUnmodifiable_pattern() {
assertIteratorIsUnmodifiable(Splitter.on(Pattern.compile(",")).split("a,b").iterator());
}
private void assertIteratorIsUnmodifiable(Iterator<?> iterator) {
iterator.next();
try {
iterator.remove();
fail();
} catch (UnsupportedOperationException expected) {
}
}
public void testSplitterIterableIsLazy_char() {
assertSplitterIterableIsLazy(COMMA_SPLITTER);
}
public void testSplitterIterableIsLazy_string() {
assertSplitterIterableIsLazy(Splitter.on(","));
}
/**
* This test really pushes the boundaries of what we support. In general the splitter's behaviour
* is not well defined if the char sequence it's splitting is mutated during iteration.
*/
private void assertSplitterIterableIsLazy(Splitter splitter) {
StringBuilder builder = new StringBuilder();
Iterator<String> iterator = splitter.split(builder).iterator();
builder.append("A,");
assertEquals("A", iterator.next());
builder.append("B,");
assertEquals("B", iterator.next());
builder.append("C");
assertEquals("C", iterator.next());
assertFalse(iterator.hasNext());
}
public void testFixedLengthSimpleSplit() {
String simple = "abcde";
Iterable<String> letters = Splitter.fixedLength(2).split(simple);
assertThat(letters).containsExactly("ab", "cd", "e").inOrder();
}
public void testFixedLengthSplitEqualChunkLength() {
String simple = "abcdef";
Iterable<String> letters = Splitter.fixedLength(2).split(simple);
assertThat(letters).containsExactly("ab", "cd", "ef").inOrder();
}
public void testFixedLengthSplitOnlyOneChunk() {
String simple = "abc";
Iterable<String> letters = Splitter.fixedLength(3).split(simple);
assertThat(letters).containsExactly("abc").inOrder();
}
public void testFixedLengthSplitSmallerString() {
String simple = "ab";
Iterable<String> letters = Splitter.fixedLength(3).split(simple);
assertThat(letters).containsExactly("ab").inOrder();
}
public void testFixedLengthSplitEmptyString() {
String simple = "";
Iterable<String> letters = Splitter.fixedLength(3).split(simple);
assertThat(letters).containsExactly("").inOrder();
}
public void testFixedLengthSplitEmptyStringWithOmitEmptyStrings() {
assertThat(Splitter.fixedLength(3).omitEmptyStrings().split("")).isEmpty();
}
public void testFixedLengthSplitIntoChars() {
String simple = "abcd";
Iterable<String> letters = Splitter.fixedLength(1).split(simple);
assertThat(letters).containsExactly("a", "b", "c", "d").inOrder();
}
public void testFixedLengthSplitZeroChunkLen() {
try {
Splitter.fixedLength(0);
fail();
} catch (IllegalArgumentException expected) {
}
}
public void testFixedLengthSplitNegativeChunkLen() {
try {
Splitter.fixedLength(-1);
fail();
} catch (IllegalArgumentException expected) {
}
}
public void testLimitLarge() {
String simple = "abcd";
Iterable<String> letters = Splitter.fixedLength(1).limit(100).split(simple);
assertThat(letters).containsExactly("a", "b", "c", "d").inOrder();
}
public void testLimitOne() {
String simple = "abcd";
Iterable<String> letters = Splitter.fixedLength(1).limit(1).split(simple);
assertThat(letters).containsExactly("abcd").inOrder();
}
public void testLimitFixedLength() {
String simple = "abcd";
Iterable<String> letters = Splitter.fixedLength(1).limit(2).split(simple);
assertThat(letters).containsExactly("a", "bcd").inOrder();
}
public void testLimit1Separator() {
String simple = "a,b,c,d";
Iterable<String> items = COMMA_SPLITTER.limit(1).split(simple);
assertThat(items).containsExactly("a,b,c,d").inOrder();
}
public void testLimitSeparator() {
String simple = "a,b,c,d";
Iterable<String> items = COMMA_SPLITTER.limit(2).split(simple);
assertThat(items).containsExactly("a", "b,c,d").inOrder();
}
public void testLimitExtraSeparators() {
String text = "a,,,b,,c,d";
Iterable<String> items = COMMA_SPLITTER.limit(2).split(text);
assertThat(items).containsExactly("a", ",,b,,c,d").inOrder();
}
public void testLimitExtraSeparatorsOmitEmpty() {
String text = "a,,,b,,c,d";
Iterable<String> items = COMMA_SPLITTER.limit(2).omitEmptyStrings().split(text);
assertThat(items).containsExactly("a", "b,,c,d").inOrder();
}
public void testLimitExtraSeparatorsOmitEmpty3() {
String text = "a,,,b,,c,d";
Iterable<String> items = COMMA_SPLITTER.limit(3).omitEmptyStrings().split(text);
assertThat(items).containsExactly("a", "b", "c,d").inOrder();
}
public void testLimitExtraSeparatorsTrim() {
String text = ",,a,, , b ,, c,d ";
Iterable<String> items = COMMA_SPLITTER.limit(2).omitEmptyStrings().trimResults().split(text);
assertThat(items).containsExactly("a", "b ,, c,d").inOrder();
}
public void testLimitExtraSeparatorsTrim3() {
String text = ",,a,, , b ,, c,d ";
Iterable<String> items = COMMA_SPLITTER.limit(3).omitEmptyStrings().trimResults().split(text);
assertThat(items).containsExactly("a", "b", "c,d").inOrder();
}
public void testLimitExtraSeparatorsTrim1() {
String text = ",,a,, , b ,, c,d ";
Iterable<String> items = COMMA_SPLITTER.limit(1).omitEmptyStrings().trimResults().split(text);
assertThat(items).containsExactly("a,, , b ,, c,d").inOrder();
}
public void testLimitExtraSeparatorsTrim1NoOmit() {
String text = ",,a,, , b ,, c,d ";
Iterable<String> items = COMMA_SPLITTER.limit(1).trimResults().split(text);
assertThat(items).containsExactly(",,a,, , b ,, c,d").inOrder();
}
public void testLimitExtraSeparatorsTrim1Empty() {
String text = "";
Iterable<String> items = COMMA_SPLITTER.limit(1).split(text);
assertThat(items).containsExactly("").inOrder();
}
public void testLimitExtraSeparatorsTrim1EmptyOmit() {
String text = "";
Iterable<String> items = COMMA_SPLITTER.omitEmptyStrings().limit(1).split(text);
assertThat(items).isEmpty();
}
public void testInvalidZeroLimit() {
try {
COMMA_SPLITTER.limit(0);
fail();
} catch (IllegalArgumentException expected) {
}
}
@GwtIncompatible // NullPointerTester
public void testNullPointers() {
NullPointerTester tester = new NullPointerTester();
tester.testAllPublicStaticMethods(Splitter.class);
tester.testAllPublicInstanceMethods(COMMA_SPLITTER);
tester.testAllPublicInstanceMethods(COMMA_SPLITTER.trimResults());
}
public void testMapSplitter_trimmedBoth() {
Map<String, String> m =
COMMA_SPLITTER
.trimResults()
.withKeyValueSeparator(Splitter.on(':').trimResults())
.split("boy : tom , girl: tina , cat : kitty , dog: tommy ");
ImmutableMap<String, String> expected =
ImmutableMap.of("boy", "tom", "girl", "tina", "cat", "kitty", "dog", "tommy");
assertThat(m).isEqualTo(expected);
assertThat(m.entrySet()).containsExactlyElementsIn(expected.entrySet()).inOrder();
}
public void testMapSplitter_trimmedEntries() {
Map<String, String> m =
COMMA_SPLITTER
.trimResults()
.withKeyValueSeparator(":")
.split("boy : tom , girl: tina , cat : kitty , dog: tommy ");
ImmutableMap<String, String> expected =
ImmutableMap.of("boy ", " tom", "girl", " tina", "cat ", " kitty", "dog", " tommy");
assertThat(m).isEqualTo(expected);
assertThat(m.entrySet()).containsExactlyElementsIn(expected.entrySet()).inOrder();
}
public void testMapSplitter_trimmedKeyValue() {
Map<String, String> m =
COMMA_SPLITTER
.withKeyValueSeparator(Splitter.on(':').trimResults())
.split("boy : tom , girl: tina , cat : kitty , dog: tommy ");
ImmutableMap<String, String> expected =
ImmutableMap.of("boy", "tom", "girl", "tina", "cat", "kitty", "dog", "tommy");
assertThat(m).isEqualTo(expected);
assertThat(m.entrySet()).containsExactlyElementsIn(expected.entrySet()).inOrder();
}
public void testMapSplitter_notTrimmed() {
Map<String, String> m =
COMMA_SPLITTER
.withKeyValueSeparator(":")
.split(" boy:tom , girl: tina , cat :kitty , dog: tommy ");
ImmutableMap<String, String> expected =
ImmutableMap.of(" boy", "tom ", " girl", " tina ", " cat ", "kitty ", " dog", " tommy ");
assertThat(m).isEqualTo(expected);
assertThat(m.entrySet()).containsExactlyElementsIn(expected.entrySet()).inOrder();
}
public void testMapSplitter_CharacterSeparator() {
// try different delimiters.
Map<String, String> m =
Splitter.on(",").withKeyValueSeparator(':').split("boy:tom,girl:tina,cat:kitty,dog:tommy");
ImmutableMap<String, String> expected =
ImmutableMap.of("boy", "tom", "girl", "tina", "cat", "kitty", "dog", "tommy");
assertThat(m).isEqualTo(expected);
assertThat(m.entrySet()).containsExactlyElementsIn(expected.entrySet()).inOrder();
}
public void testMapSplitter_multiCharacterSeparator() {
// try different delimiters.
Map<String, String> m =
Splitter.on(",")
.withKeyValueSeparator(":^&")
.split("boy:^&tom,girl:^&tina,cat:^&kitty,dog:^&tommy");
ImmutableMap<String, String> expected =
ImmutableMap.of("boy", "tom", "girl", "tina", "cat", "kitty", "dog", "tommy");
assertThat(m).isEqualTo(expected);
assertThat(m.entrySet()).containsExactlyElementsIn(expected.entrySet()).inOrder();
}
public void testMapSplitter_emptySeparator() {
try {
COMMA_SPLITTER.withKeyValueSeparator("");
fail();
} catch (IllegalArgumentException expected) {
}
}
public void testMapSplitter_malformedEntry() {
try {
COMMA_SPLITTER.withKeyValueSeparator("=").split("a=1,b,c=2");
fail();
} catch (IllegalArgumentException expected) {
}
}
/**
* Testing the behavior in https://github.com/google/guava/issues/1900 - this behavior may want to
* be changed?
*/
public void testMapSplitter_extraValueDelimiter() {
try {
COMMA_SPLITTER.withKeyValueSeparator("=").split("a=1,c=2=");
fail();
} catch (IllegalArgumentException expected) {
}
}
public void testMapSplitter_orderedResults() {
Map<String, String> m =
COMMA_SPLITTER.withKeyValueSeparator(":").split("boy:tom,girl:tina,cat:kitty,dog:tommy");
assertThat(m.keySet()).containsExactly("boy", "girl", "cat", "dog").inOrder();
assertThat(m)
.isEqualTo(ImmutableMap.of("boy", "tom", "girl", "tina", "cat", "kitty", "dog", "tommy"));
// try in a different order
m = COMMA_SPLITTER.withKeyValueSeparator(":").split("girl:tina,boy:tom,dog:tommy,cat:kitty");
assertThat(m.keySet()).containsExactly("girl", "boy", "dog", "cat").inOrder();
assertThat(m)
.isEqualTo(ImmutableMap.of("boy", "tom", "girl", "tina", "cat", "kitty", "dog", "tommy"));
}
public void testMapSplitter_duplicateKeys() {
try {
COMMA_SPLITTER.withKeyValueSeparator(":").split("a:1,b:2,a:3");
fail();
} catch (IllegalArgumentException expected) {
}
}
public void testMapSplitter_varyingTrimLevels() {
MapSplitter splitter = COMMA_SPLITTER.trimResults().withKeyValueSeparator(Splitter.on("->"));
Map<String, String> split = splitter.split(" x -> y, z-> a ");
assertThat(split).containsEntry("x ", " y");
assertThat(split).containsEntry("z", " a");
}
}
7.Strings字符串处理
Strings
类中存在数量有限的通用String
字符串工具。
与
String
或CharSequence
实例有关的静态工具方法。
7.1静态方法
方法 | 描述 |
---|---|
StringnullToEmpty(@NullableStringstring) | 如果给定的字符串为非null,则返回该字符串;否则为空字符串。 |
StringemptyToNull(@NullableStringstring) | 如果给定的字符串非空,则返回该字符串;否则为null。 |
booleanisNullOrEmpty(@NullableStringstring) | 如果给定的字符串为null或为空字符串,则返回true。考虑使用nullToEmpty规范化字符串引用。如果这样做,则可以使用String.isEmpty()代替此方法,并且也不需要特殊的null安全形式的方法,例如String.toUpperCase。或者,如果想"以另一种方式"进行标准化,则将空字符串转换为null,则可以使用emptyToNull。 |
StringpadStart(Stringstring,intminLength,charpadChar) | 返回一个长度至少为minLength的字符串,该字符串由string组成, 前缀 为达到该长度所需的padChar副本。例如,padStart("7",3,'0')returns"007";padStart("2010",3,'0')returns"2010"请参阅java.util.Formatter,以获取更多的格式化功能。 |
StringpadEnd(Stringstring,intminLength,charpadChar) | 返回长度至少为minLength的字符串,该字符串由string组成, 附加 了达到该长度所需的padChar副本。例如,padEnd("4.",5,'0')returns"4.000";padEnd("2010",3,'!')returns"2010"请参阅java.util.Formatter,以获取更多的格式化功能。 |
Stringrepeat(Stringstring,intcount) | 返回由输入字符串的特定数量的级联副本组成的字符串。例如,repeat("hey",3)返回字符串"heyheyhey"。返回一个包含string的字符串,该字符串重复了count次(如果count为零,则返回空字符串)。如果count是负数则抛出IllegalArgumentException。 |
StringcommonPrefix(CharSequencea,CharSequenceb) | 返回最长的字符串前缀,以使a.toString().startsWith(prefix)&&b.toString().startsWith(prefix),注意不要拆分代理对。如果a和b没有共同的前缀,则返回空字符串。 |
StringcommonSuffix(CharSequencea,CharSequenceb) | 返回最长的字符串后缀,以使a.toString().endsWith(suffix)&&b.toString().endsWith(suffix),注意不要拆分代理对。如果a和b没有共同的后缀,则返回空字符串。 |
StringlenientFormat(<br/>@NullableStringtemplate,@NullableObject@Nullable...args) | 返回给定的template字符串,其中每次出现的"%s"被args中的相应参数值替换;或者,如果占位符和参数计数不匹配,则返回该字符串的尽力而为形式。在正常情况下不会抛出异常。 注意: 对于大多数字符串格式需求,请使用String.format,java.io.PrintWriter.format和相关方法。这些支持全部格式说明符,并提醒你通过抛出java.util.IllegalFormatException来解决使用错误。在某些情况下,例如输出调试信息或构造用于另一个未经检查的异常的消息,字符串格式化期间的异常除了取代你试图提供的真实信息外,几乎没有什么用处。这些就是这种方法适用的情况;相反,它会生成带有所有提供的参数值的尽力而为字符串。此方法在String.format不可用的GWT等环境中也很有用。例如,出于上述两个原因,Preconditions类的方法实现使用此格式化程序。 警告: 仅识别精确的两个字符的占位符序列"%s"。 |
7.2使用示例
import com.google.common.annotations.GwtIncompatible;
import com.google.common.base.Strings;
import com.google.common.testing.NullPointerTester;
import junit.framework.TestCase;
import static com.google.common.truth.Truth.assertThat;
public class StringsTest extends TestCase {
public void testNullToEmpty() {
assertEquals("", Strings.nullToEmpty(null));
assertEquals("", Strings.nullToEmpty(""));
assertEquals("a", Strings.nullToEmpty("a"));
}
public void testEmptyToNull() {
assertNull(Strings.emptyToNull(null));
assertNull(Strings.emptyToNull(""));
assertEquals("a", Strings.emptyToNull("a"));
}
public void testIsNullOrEmpty() {
assertTrue(Strings.isNullOrEmpty(null));
assertTrue(Strings.isNullOrEmpty(""));
assertFalse(Strings.isNullOrEmpty("a"));
}
public void testPadStart_noPadding() {
assertSame("", Strings.padStart("", 0, '-'));
assertSame("x", Strings.padStart("x", 0, '-'));
assertSame("x", Strings.padStart("x", 1, '-'));
assertSame("xx", Strings.padStart("xx", 0, '-'));
assertSame("xx", Strings.padStart("xx", 2, '-'));
}
public void testPadStart_somePadding() {
assertEquals("-", Strings.padStart("", 1, '-'));
assertEquals("--", Strings.padStart("", 2, '-'));
assertEquals("-x", Strings.padStart("x", 2, '-'));
assertEquals("--x", Strings.padStart("x", 3, '-'));
assertEquals("-xx", Strings.padStart("xx", 3, '-'));
}
public void testPadStart_negativeMinLength() {
assertSame("x", Strings.padStart("x", -1, '-'));
}
public void testPadStart_null() {
try {
Strings.padStart(null, 5, '0');
fail();
} catch (NullPointerException expected) {
}
}
public void testPadEnd_noPadding() {
assertSame("", Strings.padEnd("", 0, '-'));
assertSame("x", Strings.padEnd("x", 0, '-'));
assertSame("x", Strings.padEnd("x", 1, '-'));
assertSame("xx", Strings.padEnd("xx", 0, '-'));
assertSame("xx", Strings.padEnd("xx", 2, '-'));
}
public void testPadEnd_somePadding() {
assertEquals("-", Strings.padEnd("", 1, '-'));
assertEquals("--", Strings.padEnd("", 2, '-'));
assertEquals("x-", Strings.padEnd("x", 2, '-'));
assertEquals("x--", Strings.padEnd("x", 3, '-'));
assertEquals("xx-", Strings.padEnd("xx", 3, '-'));
}
public void testPadEnd_negativeMinLength() {
assertSame("x", Strings.padEnd("x", -1, '-'));
}
public void testPadEnd_null() {
try {
Strings.padEnd(null, 5, '0');
fail();
} catch (NullPointerException expected) {
}
}
public void testRepeat() {
String input = "20";
assertEquals("", Strings.repeat(input, 0));
assertEquals("20", Strings.repeat(input, 1));
assertEquals("2020", Strings.repeat(input, 2));
assertEquals("202020", Strings.repeat(input, 3));
assertEquals("", Strings.repeat("", 4));
for (int i = 0; i < 100; ++i) {
assertEquals(2 * i, Strings.repeat(input, i).length());
}
try {
Strings.repeat("x", -1);
fail();
} catch (IllegalArgumentException expected) {
}
try {
// Massive string
Strings.repeat("12345678", (1 << 30) + 3);
fail();
} catch (ArrayIndexOutOfBoundsException expected) {
}
}
public void testRepeat_null() {
try {
Strings.repeat(null, 5);
fail();
} catch (NullPointerException expected) {
}
}
public void testCommonPrefix() {
assertEquals("", Strings.commonPrefix("", ""));
assertEquals("", Strings.commonPrefix("abc", ""));
assertEquals("", Strings.commonPrefix("", "abc"));
assertEquals("", Strings.commonPrefix("abcde", "xyz"));
assertEquals("", Strings.commonPrefix("xyz", "abcde"));
assertEquals("", Strings.commonPrefix("xyz", "abcxyz"));
assertEquals("a", Strings.commonPrefix("abc", "aaaaa"));
assertEquals("aa", Strings.commonPrefix("aa", "aaaaa"));
assertEquals("abc", Strings.commonPrefix(new StringBuffer("abcdef"), "abcxyz"));
// Identical valid surrogate pairs.
assertEquals(
"abc\uD8AB\uDCAB", Strings.commonPrefix("abc\uD8AB\uDCABdef", "abc\uD8AB\uDCABxyz"));
// Differing valid surrogate pairs.
assertEquals("abc", Strings.commonPrefix("abc\uD8AB\uDCABdef", "abc\uD8AB\uDCACxyz"));
// One invalid pair.
assertEquals("abc", Strings.commonPrefix("abc\uD8AB\uDCABdef", "abc\uD8AB\uD8ABxyz"));
// Two identical invalid pairs.
assertEquals(
"abc\uD8AB\uD8AC", Strings.commonPrefix("abc\uD8AB\uD8ACdef", "abc\uD8AB\uD8ACxyz"));
// Two differing invalid pairs.
assertEquals("abc\uD8AB", Strings.commonPrefix("abc\uD8AB\uD8ABdef", "abc\uD8AB\uD8ACxyz"));
// One orphan high surrogate.
assertEquals("", Strings.commonPrefix("\uD8AB\uDCAB", "\uD8AB"));
// Two orphan high surrogates.
assertEquals("\uD8AB", Strings.commonPrefix("\uD8AB", "\uD8AB"));
}
public void testCommonSuffix() {
assertEquals("", Strings.commonSuffix("", ""));
assertEquals("", Strings.commonSuffix("abc", ""));
assertEquals("", Strings.commonSuffix("", "abc"));
assertEquals("", Strings.commonSuffix("abcde", "xyz"));
assertEquals("", Strings.commonSuffix("xyz", "abcde"));
assertEquals("", Strings.commonSuffix("xyz", "xyzabc"));
assertEquals("c", Strings.commonSuffix("abc", "ccccc"));
assertEquals("aa", Strings.commonSuffix("aa", "aaaaa"));
assertEquals("abc", Strings.commonSuffix(new StringBuffer("xyzabc"), "xxxabc"));
// Identical valid surrogate pairs.
assertEquals(
"\uD8AB\uDCABdef", Strings.commonSuffix("abc\uD8AB\uDCABdef", "xyz\uD8AB\uDCABdef"));
// Differing valid surrogate pairs.
assertEquals("def", Strings.commonSuffix("abc\uD8AB\uDCABdef", "abc\uD8AC\uDCABdef"));
// One invalid pair.
assertEquals("def", Strings.commonSuffix("abc\uD8AB\uDCABdef", "xyz\uDCAB\uDCABdef"));
// Two identical invalid pairs.
assertEquals(
"\uD8AB\uD8ABdef", Strings.commonSuffix("abc\uD8AB\uD8ABdef", "xyz\uD8AB\uD8ABdef"));
// Two differing invalid pairs.
assertEquals("\uDCABdef", Strings.commonSuffix("abc\uDCAB\uDCABdef", "abc\uDCAC\uDCABdef"));
// One orphan low surrogate.
assertEquals("", Strings.commonSuffix("x\uD8AB\uDCAB", "\uDCAB"));
// Two orphan low surrogates.
assertEquals("\uDCAB", Strings.commonSuffix("\uDCAB", "\uDCAB"));
}
public void testLenientFormat() {
assertEquals("%s", Strings.lenientFormat("%s"));
assertEquals("5", Strings.lenientFormat("%s", 5));
assertEquals("foo [5]", Strings.lenientFormat("foo", 5));
assertEquals("foo [5, 6, 7]", Strings.lenientFormat("foo", 5, 6, 7));
assertEquals("%s 1 2", Strings.lenientFormat("%s %s %s", "%s", 1, 2));
assertEquals(" [5, 6]", Strings.lenientFormat("", 5, 6));
assertEquals("123", Strings.lenientFormat("%s%s%s", 1, 2, 3));
assertEquals("1%s%s", Strings.lenientFormat("%s%s%s", 1));
assertEquals("5 + 6 = 11", Strings.lenientFormat("%s + 6 = 11", 5));
assertEquals("5 + 6 = 11", Strings.lenientFormat("5 + %s = 11", 6));
assertEquals("5 + 6 = 11", Strings.lenientFormat("5 + 6 = %s", 11));
assertEquals("5 + 6 = 11", Strings.lenientFormat("%s + %s = %s", 5, 6, 11));
assertEquals("null [null, null]", Strings.lenientFormat("%s", null, null, null));
assertEquals("null [5, 6]", Strings.lenientFormat(null, 5, 6));
assertEquals("null", Strings.lenientFormat("%s", (Object) null));
assertEquals("(Object[])null", Strings.lenientFormat("%s", (Object[]) null));
}
@GwtIncompatible // GWT reflection includes less data
public void testLenientFormat_badArgumentToString() {
assertThat(Strings.lenientFormat("boiler %s plate", new ThrowsOnToString()))
.matches(
"boiler <com\\.google\\.common\\.base\\.StringsTest\\$ThrowsOnToString@[0-9a-f]+ "
+ "threw java\\.lang\\.UnsupportedOperationException> plate");
}
public void testLenientFormat_badArgumentToString_gwtFriendly() {
assertThat(Strings.lenientFormat("boiler %s plate", new ThrowsOnToString()))
.matches("boiler <.*> plate");
}
private static class ThrowsOnToString {
@Override
public String toString() {
throw new UnsupportedOperationException();
}
}
@GwtIncompatible // NullPointerTester
public void testNullPointers() {
NullPointerTester tester = new NullPointerTester();
tester.testAllPublicStaticMethods(Strings.class);
}
}
本文参考:
CharMatcher
Charsets
CaseFormat
Joiner
Splitter
Strings
guava-tests-base
Java 面试宝典是大明哥全力打造的 Java 精品面试题,它是一份靠谱、强大、详细、经典的 Java 后端面试宝典。它不仅仅只是一道道面试题,而是一套完整的 Java 知识体系,一套你 Java 知识点的扫盲贴。
它的内容包括:
- 大厂真题:Java 面试宝典里面的题目都是最近几年的高频的大厂面试真题。
- 原创内容:Java 面试宝典内容全部都是大明哥原创,内容全面且通俗易懂,回答部分可以直接作为面试回答内容。
- 持续更新:一次购买,永久有效。大明哥会持续更新 3+ 年,累计更新 1000+,宝典会不断迭代更新,保证最新、最全面。
- 覆盖全面:本宝典累计更新 1000+,从 Java 入门到 Java 架构的高频面试题,实现 360° 全覆盖。
- 不止面试:内容包含面试题解析、内容详解、知识扩展,它不仅仅只是一份面试题,更是一套完整的 Java 知识体系。
- 宝典详情:https://www.yuque.com/chenssy/sike-java/xvlo920axlp7sf4k
- 宝典总览:https://www.yuque.com/chenssy/sike-java/yogsehzntzgp4ly1
- 宝典进展:https://www.yuque.com/chenssy/sike-java/en9ned7loo47z5aw
目前 Java 面试宝典累计更新 400+ 道,总字数 42w+。大明哥还在持续更新中,下图是大明哥在 2024-12 月份的更新情况:
想了解详情的小伙伴,扫描下面二维码加大明哥微信【daming091】咨询
同时,大明哥也整理一套目前市面最常见的热点面试题。微信搜[大明哥聊 Java]或扫描下方二维码关注大明哥的原创公众号[大明哥聊 Java] ,回复【面试题】 即可免费领取。