字符串是在程序开发中最常见的,经过多年不断积累,相关的工具类已经非常庞大,为了方便大家了解,这里根据个人开发经验,进行整理和归类,提供方便、简化的字符串处理方法,以支持大家在应用程序中更轻松地处理字符串。当然,日常开发中一般不会自己去编写工具类,更多是使用已经比较成熟的第三方库中提供的工具类,例如org.apache.commons.lang.StringUtils。
基本概念
几个概念先明确下:
1.null:String是引用类型而不是基本类型,所以取值可以为null
2.空串:即不包含任何元素的字符串,表示为""
3.空格:即" ",对应ascii码是32
4.空白字符:是一组非可见的字符,对于文本处理来说,除了空格外,通常包括tab(\t)、回车(\r)、换行(\n)、垂直制表符(\v)、换页符(\f),当然,windows系统常用的回车换行的组合(\r\n)也算在其中。
1 判断与验证
根据特定规则判断,不改变字符串自身
1.1判断是否包含内容
1)isEmpty和isNotEmpty方法
判断是否为null或空串
/**
* 判断字符串是否为空(null或空串)
*
* @param str 要判断的字符串
* @return 如果字符串为空则返回true,否则返回false
*/
public static boolean isEmpty(String str) {
return str == null || str.isEmpty();
}
/**
* 判断字符串是否不为空(null或空串)
*
* @param str 要判断的字符串
* @return 如果字符串为空则返回true,否则返回false
*/
public static boolean isNotEmpty(String str) {
return !isEmpty(str);
}
示例
StringUtils.isEmpty(null); // true
StringUtils.isEmpty(""); // true
StringUtils.isEmpty(" "); // false
StringUtils.isEmpty("not empty"); // false
2)isBlank和isNotBlank方法
包含所有空白字符(空格、tab、换行、回车等)的判定
/**
* 判断字符串是否为空白
*
* @param str
* @return
*/
public static boolean isBlank(String str) {
if(str == null || str.length() == 0){
return true;
} else {
for(char c : str.toCharArray()) {
if (!Character.isWhitespace(c)) {
return false;
}
}
return true;
}
}
/**
* 判断字符串是否不为空白
*
* @param str
* @return
*/
public static boolean isNotBlank(String str) {
return !isBlank(str);
}
3)hasLength方法
检查字符串是否有长度(非null且长度大于0)
/**
* 检查字符串是否有长度(非 null 且长度大于 0)
*
* @param str
* @return
*/
public static boolean hasLength(String str) {
return str != null && !str.isEmpty();
}
/**
* 检查字符串是否有长度(非 null 且长度大于 0)
*
* @param str
* @return
*/
public static boolean hasLength(CharSequence str) {
return str != null && str.length() > 0;
}
示例
StringUtils.hasLength(null); // false
StringUtils.hasLength(""); // false
StringUtils.hasLength(" "); // true
StringUtils.hasLength("not empty"); // true
1.2 比较字符串
基本用法equals、equalsIgnoreCase、compare、compareIgnoreCase
1)equals和equalsIgnoreCase方法:
/**
* 判断两个字符串是否相等
*
* @param str1 字符串1
* @param str2 字符串2
* @return 如果两个字符串相等则返回true,否则返回false
*/
public static boolean equals(String str1, String str2) {
if (str1 == str2) {
return true;
} else if (str1 != null && str2 != null) {
return str1.equals(str2);
} else {
return false;
}
}
/**
* 判断两个字符串是否相等(忽略大小写)
*
* @param str1 字符串1
* @param str2 字符串2
* @return 如果两个字符串相等则返回true,否则返回false
*/
public static boolean equalsIgnoreCase(String str1, String str2) {
if (str1 == str2) {
return true;
} else if (str1 != null && str2 != null) {
return str1.equalsIgnoreCase(str2);
} else {
return false;
}
}
注:
一般情况下String字符串和数组都不是基本数据类型,它们被当作类来处理,也就是我们所说的引用数据类型。对基本类型而言,使用==进行比较,是直接比较两个数据类型之间的数值;对于引用类型而言,使用==进行比较,是比较的两个数据类型之间的地址。因此我们比较字符串的时候,需要使用str.equals(str2) 而不是直接使用==进行比较。
//下面我们来了解字符串的常量池
String str="gre";
String str2="gre";
char[] chars={'g','r','e'};
String arraychar=new String(chars);
System.out.println(str==str2);//true
System.out.println(str==arraychar);//false
System.out.println(str2==arraychar);//false
对于前面两个定义str和str2而言,str和str2当中所保存字符由于是相同的,因此jvm为了节约内存,就让这个字母在内存当中的地址是相同的,在java当中字符串是不可修改的缘故,因此str和str2指向的是同一个内存空间,在这个内存空间当中我们爆保存的是gre这三个单词的ASCii码,which are 97,98,99。而对于使用char所创建的String而言,我们开启了一个新的内存空间,因为在内存当中我们保存的是char型字符,which are 'g','r','e',在内存当中保存的东西不一样了,因此地址也就不一样了。我们用于比较的时候字符串又是引用类型,因此最后比较的是地址,地址不一样就会输出false,这也是会最终呈持续的后面两行会输出false的缘故。
2)compare和compareIgnoreCase方法:
/**
* 比较两个字符串的大小
*
* @param str1 字符串1
* @param str2 字符串2
* @return 返回一个整数值,用于表示比较的结果
*/
public static int compare(String str1, String str2) {
return compare(str1, str2, true);
}
/**
* 比较两个字符串的大小
*
* @param str1 字符串1
* @param str2 字符串2
* @param nullIsLess null值是是否是小值
* @return 返回一个整数值,用于表示比较的结果。如果star1小于star2,则返回负数;如果star1等于star2,则返回0;;如果star1大于star2,则返回正数
*/
public static int compare(String str1, String str2, boolean nullIsLess) {
if (str1 == str2) {
return 0;
} else if (str1 == null) {
return nullIsLess ? -1 : 1;
} else if (str2 == null) {
return nullIsLess ? 1 : -1;
} else {
return str1.compareTo(str2);
}
}
/**
* 比较两个字符串的大小(忽略大小写)
*
* @param str1 字符串1
* @param str2 字符串2
* @return 返回一个整数值,用于表示比较的结果
*/
public static int compareIgnoreCase(String str1, String str2) {
return compareIgnoreCase(str1, str2, true);
}
/**
* 比较两个字符串的大小(忽略大小写)
*
* @param str1 字符串1
* @param str2 字符串2
* @param nullIsLess null值是是否是小值
* @return 返回一个整数值,用于表示比较的结果。如果star1小于star2,则返回负数;如果star1等于star2,则返回0;;如果star1大于star2,则返回正数
*/
public static int compareIgnoreCase(String str1, String str2, boolean nullIsLess) {
if (str1 == str2) {
return 0;
} else if (str1 == null) {
return nullIsLess ? -1 : 1;
} else if (str2 == null) {
return nullIsLess ? 1 : -1;
} else {
return str1.compareToIgnoreCase(str2);
}
}
1.3 检验字符串
通过一系列实现好的方法,来快速返回是否符合特定规则。
1)isNumeric和isNumericSpace方法(注意:小数点和正负号,都会判定为false)
/**
* 判断字符串是否为数字
*
* @param str 要判断的字符串
* @return 如果字符串为数字则返回true,否则返回false
*/
public static boolean isNumeric(String str) {
if (isEmpty(str)) {
return false;
}
for (char c : str.toCharArray()) {
if (!Character.isDigit(c)) {
return false;
}
}
return true;
}
/**
* 判断字符串是否只包含数字和空格
*
* @param str 要判断的字符串
* @return 如果字符串为数字则返回true,否则返回false
*/
public static boolean isNumericSpace(String str) {
if (str == null) {
return false;
} else {
for (char c : str.toCharArray()) {
if (c != ' ' && !Character.isDigit(c)) {
return false;
}
}
return true;
}
}
2)isWhitespace方法
/**
* 判定是否只包括空白字符
*
* @param str
* @return
*/
public static boolean isWhitespace(String str) {
if (str == null) {
return false;
} else {
for (char c : str.toCharArray()) {
if (!Character.isWhitespace(c)) {
return false;
}
}
return true;
}
}
3)isAllUpperCase、isAllLowerCase和isMixedCase方法
/**
* 判定是否全部为大写
*
* @param str
* @return
*/
public static boolean isAllUpperCase(String str) {
if (isEmpty(str)) {
return false;
} else {
for (char c : str.toCharArray()) {
if (!Character.isUpperCase(c)) {
return false;
}
}
return true;
}
}
/**
* 判定是否全部为小写
*
* @param str
* @return
*/
public static boolean isAllLowerCase(String str) {
if (isEmpty(str)) {
return false;
} else {
for (char c : str.toCharArray()) {
if (!Character.isLowerCase(c)) {
return false;
}
}
return true;
}
}
/**
* 判定是否混合大小写(注意:包含其他字符,如空格,不影响结果判定)
*
* @param str
* @return
*/
public static boolean isMixedCase(String str) {
if (!isEmpty(str) && str.length() != 1) {
boolean containsUppercase = false;
boolean containsLowercase = false;
for (char c : str.toCharArray()) {
if (containsUppercase && containsLowercase) {
return true;
}
if (Character.isUpperCase(c)) {
containsUppercase = true;
} else if (Character.isLowerCase(c)) {
containsLowercase = true;
}
}
return containsUppercase && containsLowercase;
} else {
return false;
}
}
1.4 包含字符串
1)contains方法
/**
* 判断字符串是否包含指定子字符串
*
* @param str 要判断的字符串
* @param searchStr 子字符串
* @return 如果字符串包含指定子字符串则返回true,否则返回false
*/
public static boolean contains(String str, String searchStr) {
if (str != null && searchStr != null) {
return str.contains(searchStr);
} else {
return false;
}
}
2)containsWhitespace方法
/**
* 判断是否包含空白字符串
*
* @param str
* @return
*/
public static boolean containsWhitespace(String str) {
if (isEmpty(str)) {
return false;
} else {
for(char c : str.toCharArray()){
if (Character.isWhitespace(c)) {
return true;
}
}
return false;
}
}
1.5 起止字符判定
1)startsWith 和 startsWithIgnoreCase方法
/**
* 判断字符串是否以指定的前缀开始
*
* @param str 要判断的字符串
* @param prefix 前缀
* @return 如果字符串以指定的前缀开始则返回true,否则返回false
*/
public static boolean startsWith(String str, String prefix) {
if (str != null && prefix != null) {
return str.startsWith(prefix);
} else {
return str == prefix;
}
}
/**
* 判断字符串是否以指定的前缀开始(忽略大小写)
*
* @param str 要判断的字符串
* @param prefix 前缀
* @return 如果字符串以指定的前缀开始则返回true,否则返回false
*/
public static boolean startsWithIgnoreCase(String str, String prefix) {
return str != null && prefix != null && str.length() >= prefix.length() && str.regionMatches(true, 0, prefix, 0, prefix.length());
}
2)endsWith 和 endsWithIgnoreCase方法
/**
* 判断字符串是否以指定的后缀结束
*
* @param str 要判断的字符串
* @param suffix 后缀
* @return 如果字符串以指定的后缀结束则返回true,否则返回false
*/
public static boolean endsWith(String str, String suffix) {
if (str != null && suffix != null) {
return str.endsWith(suffix);
} else {
return str == suffix;
}
}
/**
* 判断字符串是否以指定的后缀结束(忽略大小写)
*
* @param str 要判断的字符串
* @param suffix 后缀
* @return 如果字符串以指定的后缀结束则返回true,否则返回false
*/
public static boolean endsWithIgnoreCase(String str, String suffix) {
return str != null && suffix != null && str.length() >= suffix.length() && str.regionMatches(true, str.length() - suffix.length(), suffix, 0, suffix.length());
}
2 处理字符串
不改变字符串实质内容,对首尾以及中间的空白字符进行处理
2.1 移除空白字符
1)trim方法
trim方法与jdk差异不大,去除首尾的包含控制字符(ascii码<=32)在内的控制字符),主要是增加了对null的处理。
/**
* 去除字符串两端的空格
*
* @param str 要处理的字符串
* @return 去除两端空格后的字符串
*/
public static String trim(String str) {
return str == null ? null : str.trim();
}
2)trimAllWhitespace方法
去除字符串中所有的空白字符(包含空格、制表符、换行符等)
/**
* 去除字符串中的所有空白字符,包括空格、制表符、换行符等
*
* @param str
* @return
*/
public static String trimAllWhitespace(String str) {
if (isEmpty(str)) {
return str;
} else {
int len = str.length();
StringBuilder sb = new StringBuilder(str.length());
for(int i = 0; i < len; ++i) {
char c = str.charAt(i);
if (!Character.isWhitespace(c)) {
sb.append(c);
}
}
return sb.toString();
}
}
3)strip和stripAll方法
strip类则做了很多增强,通过重载方法实现了很多其他功能,建议在开发中使用strip类。
注意:全角空格并不在处理范围内。
/**
* 去除字符串两端的空格
*
* @param str
* @return
*/
public static String strip(String str) {
return strip(str, (String)null);
}
/**
* 去除指定字符串
*
* @param str
* @param stripChars
* @return
*/
public static String strip(String str, String stripChars) {
str = stripStart(str, stripChars);
return stripEnd(str, stripChars);
}
public static String stripStart(String str, String stripChars) {
int strLen = str == null ? 0 : str.length();
if (strLen == 0) {
return str;
} else {
int start = 0;
if (stripChars == null) {
while(start != strLen && Character.isWhitespace(str.charAt(start))) {
++start;
}
} else {
if (stripChars.isEmpty()) {
return str;
}
while(start != strLen && stripChars.indexOf(str.charAt(start)) != -1) {
++start;
}
}
return str.substring(start);
}
}
public static String stripEnd(String str, String stripChars) {
int end = str == null ? 0 : str.length();
if (end == 0) {
return str;
} else {
if (stripChars == null) {
while(end != 0 && Character.isWhitespace(str.charAt(end - 1))) {
--end;
}
} else {
if (stripChars.isEmpty()) {
return str;
}
while(end != 0 && stripChars.indexOf(str.charAt(end - 1)) != -1) {
--end;
}
}
return str.substring(0, end);
}
}
/**
* 批量去除操作
*
* @param strs
* @return
*/
public static String[] stripAll(String... strs) {
return stripAll(strs, (String)null);
}
/**
* 批量去除操作
*
* @param strs
* @param stripChars
* @return
*/
public static String[] stripAll(String[] strs, String stripChars) {
int strsLen = strs == null ? 0 : Array.getLength(strs);
if (strsLen == 0) {
return strs;
} else {
String[] newArr = new String[strsLen];
for(int i = 0; i < strsLen; ++i) {
newArr[i] = strip(strs[i], stripChars);
}
return newArr;
}
}
3)deleteWhitespace方法
对字符串基本处理的复合应用,将字符串中所有空白字符去除
/**
* 将字符串中所有空白字符去除
*
* @param str
* @return
*/
public static String deleteWhitespace(String str) {
if (isEmpty(str)) {
return str;
} else {
int sz = str.length();
char[] chs = new char[sz];
int count = 0;
for(int i = 0; i < sz; ++i) {
if (!Character.isWhitespace(str.charAt(i))) {
chs[count++] = str.charAt(i);
}
}
if (count == sz) {
return str;
} else if (count == 0) {
return "";
} else {
return new String(chs, 0, count);
}
}
}
4)normalizeSpace方法
去除首尾,但中间的空白字符,替换为单个空格
/**
* 去除首尾空白字符,但中间的空白字符,替换为单个空格
*
* @param str
* @return
*/
public static String normalizeSpace(String str) {
if (isEmpty(str)) {
return str;
} else {
int size = str.length();
char[] newChars = new char[size];
int count = 0;
int whitespacesCount = 0;
boolean startWhitespaces = true;
for(int i = 0; i < size; ++i) {
char actualChar = str.charAt(i);
boolean isWhitespace = Character.isWhitespace(actualChar);
if (isWhitespace) {
if (whitespacesCount == 0 && !startWhitespaces) {
newChars[count++] = " ".charAt(0);
}
++whitespacesCount;
} else {
startWhitespaces = false;
newChars[count++] = actualChar == 160 ? 32 : actualChar;
whitespacesCount = 0;
}
}
if (startWhitespaces) {
return "";
} else {
return (new String(newChars, 0, count - (whitespacesCount > 0 ? 1 : 0))).trim();
}
}
}
2.2 去除换行
1)chomp方法
去除结尾的一处换行符,包括三种情况 \r \n \r\n
/**
* 去除结尾的一处换行符,包括三种情况 \r \n \r\n
*
* @param str
* @return
*/
public static String chomp(String str) {
if (isEmpty(str)) {
return str;
} else if (str.length() == 1) {
char ch = str.charAt(0);
return ch != '\r' && ch != '\n' ? str : "";
} else {
int lastIdx = str.length() - 1;
char last = str.charAt(lastIdx);
if (last == '\n') {
if (str.charAt(lastIdx - 1) == '\r') {
--lastIdx;
}
} else if (last != '\r') {
++lastIdx;
}
return str.substring(0, lastIdx);
}
}
示例
StringUtils.chomp("\r") = ""
StringUtils.chomp("\n") = ""
StringUtils.chomp("\r\n") = ""
StringUtils.chomp("abc \r") = "abc "
StringUtils.chomp("abc\n") = "abc"
StringUtils.chomp("abc\r\n") = "abc"
StringUtils.chomp("abc\r\n\r\n") = "abc\r\n"
StringUtils.chomp("abc\n\r") = "abc\n"
StringUtils.chomp("abc\n\rabc") = "abc\n\rabc"
2.3 去除间隔符
去除末尾一个字符,常见使用场景是通过循环处理使用间隔符拼装的字符串,去除间隔符
注意:使用时需确保最后一位一定是间隔符,否则有可能破坏正常数据。
/**
* 去除结尾的间隔符
*
* @param str
* @return
*/
public static String chop(String str) {
if (str == null) {
return null;
} else {
int strLen = str.length();
if (strLen < 2) {
return "";
} else {
int lastIdx = strLen - 1;
String ret = str.substring(0, lastIdx);
char last = str.charAt(lastIdx);
return last == '\n' && ret.charAt(lastIdx - 1) == '\r' ? ret.substring(0, lastIdx - 1) : ret;
}
}
}
示例:
StringUtils.chop("1,2,3,") = "1,2,3"
StringUtils.chop("a") = ""
StringUtils.chop("abc") = "ab"
StringUtils.chop("abc\nabc") = "abc\nab"//此外,末尾的换行符也视为字符,如果结尾是\r\n,则一块去除,建议使用专用的chomp,以免造成非预期的结果
StringUtils.chop("\r") = ""
StringUtils.chop("\n") = ""
StringUtils.chop("\r\n") = ""
2.4 去除非数字
去除所有非数字字符,将剩余的数字字符拼接成字符串
/**
* 去除所有非数字字符,将剩余的数字字符拼接成字符串
*
* @param str
* @return
*/
public static String getDigits(String str) {
if (isEmpty(str)) {
return str;
} else {
int sz = str.length();
StringBuilder strDigits = new StringBuilder(sz);
for(int i = 0; i < sz; ++i) {
char tempChar = str.charAt(i);
if (Character.isDigit(tempChar)) {
strDigits.append(tempChar);
}
}
return strDigits.toString();
}
}
示例:
StringUtils.getDigits("abc") = ""
StringUtils.getDigits("1000$") = "1000"
StringUtils.getDigits("1123~45") = "112345"
StringUtils.getDigits("(541) 754-3010") = "5417543010"
2.4 去除子字符串
1)delete方法
/**
* 去除所有匹配的子字符串
*
* @param inString
* @param pattern
* @return
*/
public static String delete(String inString, String pattern) {
return replace(inString, pattern, "");
}
2)deleteAny方法
/**
* 去除子字符串中任意出现的字符
*
* @param inString
* @param charsToDelete
* @return
*/
public static String deleteAny(String inString, String charsToDelete) {
if (hasLength(inString) && hasLength(charsToDelete)) {
StringBuilder sb = new StringBuilder(inString.length());
for(int i = 0; i < inString.length(); ++i) {
char c = inString.charAt(i);
if (charsToDelete.indexOf(c) == -1) {
sb.append(c);
}
}
return sb.toString();
} else {
return inString;
}
}
3.查找字符串
3.1 查找字符串
1)indexOf 和 lastIndexOf方法
可搜索字符、字符串以及指定起始搜索位置,同jdk。
/**
* 搜索字符串
*
* @param str
* @param searchStr
* @return 返回第一个匹配项的索引
*/
public static int indexOf(String str, String searchStr) {
return str != null && searchStr != null ? str.indexOf(searchStr) : -1;
}
/**
* 搜索字符串以及指定起始搜索位置
*
* @param str
* @param searchStr
* @param fromIndex
* @return 返回第一个匹配项的索引
*/
public static int indexOf(String str, String searchStr, int fromIndex) {
return str != null && searchStr != null ? str.indexOf(searchStr, fromIndex) : -1;
}
/**
* 搜索字符
*
* @param str
* @param searchChar
* @return 返回第一个匹配项的索引
*/
public static int indexOf(String str, int searchChar) {
return str != null ? str.indexOf(searchChar) : -1;
}
/**
* 搜索字符以及指定起始搜索位置
*
* @param str
* @param searchChar
* @param fromIndex
* @return 返回第一个匹配项的索引
*/
public static int indexOf(String str, int searchChar, int fromIndex) {
return str != null ? str.indexOf(searchChar, fromIndex) : -1;
}
/**
* 搜索字符串
*
* @param str
* @param searchStr
* @return 返回指定字符在此字符串中最后一次出现处的索引
*/
public static int lastIndexOf(String str, String searchStr) {
return str != null && searchStr != null ? str.lastIndexOf(searchStr) : -1;
}
/**
* 搜索字符串以及指定起始搜索位置
*
* @param str
* @param searchStr
* @param fromIndex
* @return 返回指定字符在此字符串中最后一次出现处的索引
*/
public static int lastIndexOf(String str, String searchStr, int fromIndex) {
return str != null && searchStr != null ? str.lastIndexOf(searchStr, fromIndex) : -1;
}
/**
* 搜索字符
*
* @param str
* @param searchChar
* @return 返回指定字符在此字符串中最后一次出现处的索引
*/
public static int lastIndexOf(String str, int searchChar) {
return str != null ? str.lastIndexOf(searchChar) : -1;
}
/**
* 搜索字符以及指定起始搜索位置
*
* @param str
* @param searchChar
* @param fromIndex
* @return 返回指定字符在此字符串中最后一次出现处的索引
*/
public static int lastIndexOf(String str, int searchChar, int fromIndex) {
return str != null ? str.lastIndexOf(searchChar, fromIndex) : -1;
}
3.2 尾部字符串
1)unqualify方法
/**
* 获取最后一个.之后的字符串
*
* @param qualifiedName
* @return
*/
public static String unqualify(String qualifiedName) {
return unqualify(qualifiedName, '.');
}
/**
* 获取最后一个指定分隔符之后的字符串
*
* @param qualifiedName
* @param separator
* @return
*/
public static String unqualify(String qualifiedName, char separator) {
if(isNotEmpty(qualifiedName)){
int lastIndex = qualifiedName.lastIndexOf(separator);
if(lastIndex >= 0){
return qualifiedName.substring(lastIndex + 1);
}
return "";
}
return qualifiedName;
}
4.编辑字符串
字符串的分割、合并、截取、替换
4.1 分割字符串
1)split 和 splitToList方法
jdk中的split使用正则表达式匹配,而字符串分割最常用场景是如下这种根据间隔符分割
String str=“he,ll,o”;
String [] reuslt=str.split(“,”);
/**
* 将字符串按照指定分隔符拆分为数组
*
* @param str 要拆分的字符串
* @param delimiter 分隔符
* @return 拆分后的字符串数组
*/
public static String[] split(String str, String delimiter) {
if (str == null) {
return null;
} else {
return str.split(delimiter);
}
}
/**
* 将字符串按照指定分隔符拆分为列表
*
* @param str 要拆分的字符串
* @param delimiter 分隔符
* @return 拆分后的字符串列表
*/
public static List<String> splitToList(String str, String delimiter) {
if (str == null) {
return null;
} else {
return Arrays.asList(str.split(delimiter));
}
}
4.2 合并字符串
1)join方法
jdk使用concat方法,这里使用join,这是一个泛型方法,建议实际使用过程中,还是只对String使用,不要对数值类型进行合并,会导致代码可读性降低
//默认合并,注意:自动去除空白字符或null元素
/**
* 合并字符串(自动去除空白字符或null元素)
*
* @param elements
* @param <T>
* @return
*/
@SafeVarargs
public static <T> String join(T... elements) {
return join((Object[])elements, (String)null);
}
/**
* 合并字符串(自动去除空白字符或null元素)
*
* @param array
* @param delimiter
* @return
*/
public static String join(Object[] array, String delimiter) {
return array == null ? null : join((Object[])array, delimiter, 0, array.length);
}
/**
* 合并字符串(自动去除空白字符或null元素)
*
* @param array
* @param delimiter
* @param startIndex
* @param endIndex
* @return
*/
public static String join(Object[] array, String delimiter, int startIndex, int endIndex) {
if (array == null) {
return null;
} else if (endIndex - startIndex <= 0) {
return "";
} else {
StringJoiner joiner = new StringJoiner(Objects.toString(delimiter, ""));
for(int i = startIndex; i < endIndex; ++i) {
joiner.add(Objects.toString(array[i], ""));
}
return joiner.toString();
}
}
示例:
StringUtils.join(null) = null
StringUtils.join([]) = ""
StringUtils.join([null]) = ""
StringUtils.join(["a", "b", "c"]) = "abc"
StringUtils.join([null, "", "a"]) = "a"
//使用指定间隔符合并,注意:保留空白字符或null元素
StringUtils.join(["a", "b", "c"], ';') = “a;b;c”
StringUtils.join([null, "", "a"], ';') = “;;a”
4.3 截取字符串
相关方法有多个,substring和truncate基本用法同jdk,内部处理异常
1)substring方法
/**
* 截取字符串
*
* @param str
* @param start
* @return
*/
public static String substring(String str, int start) {
if (str == null) {
return null;
} else {
return str.substring(start);
}
}
/**
* 截取字符串
*
* @param str
* @param start
* @param end
* @return
*/
public static String substring(String str, int start, int end) {
if (str == null) {
return null;
} else {
return str.substring(start, end);
}
}
2)substringBefore和substringAfter方法
截取第一个指定字符前/后的字符串返回
/**
* 截取第一个指定字符前的字符串返回
*
* @param str
* @param separator
* @return
*/
public static String substringBefore(String str, int separator) {
if (isEmpty(str)) {
return str;
} else {
int pos = str.indexOf(separator);
return pos == -1 ? str : str.substring(0, pos);
}
}
/**
* 截取第一个指定字符前的字符串返回
*
* @param str
* @param separator
* @return
*/
public static String substringBefore(String str, String separator) {
if (!isEmpty(str) && separator != null) {
if (separator.isEmpty()) {
return "";
} else {
int pos = str.indexOf(separator);
return pos == -1 ? str : str.substring(0, pos);
}
} else {
return str;
}
}
/**
* 截取第一个指定字符后的字符串返回
*
* @param str
* @param separator
* @return
*/
public static String substringAfter(String str, int separator) {
if (isEmpty(str)) {
return str;
} else {
int pos = str.indexOf(separator);
return pos == -1 ? "" : str.substring(pos + 1);
}
}
/**
* 截取第一个指定字符后的字符串返回
*
* @param str
* @param separator
* @return
*/
public static String substringAfter(String str, String separator) {
if (isEmpty(str)) {
return str;
} else if (separator == null) {
return "";
} else {
int pos = str.indexOf(separator);
return pos == -1 ? "" : str.substring(pos + separator.length());
}
}
3)substringBeforeLast 和 substringAfterLast方法
截取最后一个指定字符前/后的字符串返回
/**
* 截取最后一个指定字符前的字符串返回
*
* @param str
* @param separator
* @return
*/
public static String substringBeforeLast(String str, String separator) {
if (!isEmpty(str) && !isEmpty(separator)) {
int pos = str.lastIndexOf(separator);
return pos == -1 ? str : str.substring(0, pos);
} else {
return str;
}
}
/**
* 截取最后一个指定字符后的字符串返回
*
* @param str
* @param separator
* @return
*/
public static String substringAfterLast(String str, int separator) {
if (isEmpty(str)) {
return str;
} else {
int pos = str.lastIndexOf(separator);
return pos != -1 && pos != str.length() - 1 ? str.substring(pos + 1) : "";
}
}
/**
* 截取最后一个指定字符后的字符串返回
*
* @param str
* @param separator
* @return
*/
public static String substringAfterLast(String str, String separator) {
if (isEmpty(str)) {
return str;
} else if (isEmpty(separator)) {
return "";
} else {
int pos = str.lastIndexOf(separator);
return pos != -1 && pos != str.length() - separator.length() ? str.substring(pos + separator.length()) : "";
}
}
4)substringBetween方法
/**
* 截取特定字符串中间部分
*
* @param str
* @param tag
* @return
*/
public static String substringBetween(String str, String tag) {
return substringBetween(str, tag, tag);
}
/**
* 截取特定字符串中间部分
*
* @param str
* @param open
* @param close
* @return 返回起止字符串中间的字符串,且只返回第一次匹配结果
*/
public static String substringBetween(String str, String open, String close) {
if (!ObjectUtils.allNotNull(new Object[]{str, open, close})) {
return null;
} else {
int start = str.indexOf(open);
if (start != -1) {
int end = str.indexOf(close, start + open.length());
if (end != -1) {
return str.substring(start + open.length(), end);
}
}
return null;
}
}
/**
* 截取特定字符串中间部分
*
* @param str
* @param open
* @param close
* @return 返回起止字符串中间的字符串,返回所有匹配结果
*/
public static String[] substringsBetween(String str, String open, String close) {
if (str != null && !isEmpty(open) && !isEmpty(close)) {
int strLen = str.length();
if (strLen == 0) {
return new String[0];
} else {
int closeLen = close.length();
int openLen = open.length();
List<String> list = new ArrayList();
int end;
for(int pos = 0; pos < strLen - closeLen; pos = end + closeLen) {
int start = str.indexOf(open, pos);
if (start < 0) {
break;
}
start += openLen;
end = str.indexOf(close, start);
if (end < 0) {
break;
}
list.add(str.substring(start, end));
}
return list.isEmpty() ? null : (String[])list.toArray(new String[0]);
}
} else {
return null;
}
}
5)left、right 和 mid方法
直接实现从左侧、右侧或中间截取指定位数,实用性高
/**
* 从左侧截取指定位数
*
* @param str
* @param len
* @return
*/
public static String left(String str, int len) {
if (str == null) {
return null;
} else if (len < 0) {
return "";
} else {
return str.length() <= len ? str : str.substring(0, len);
}
}
/**
* 从右侧或截取指定位数
*
* @param str
* @param len
* @return
*/
public static String right(String str, int len) {
if (str == null) {
return null;
} else if (len < 0) {
return "";
} else {
return str.length() <= len ? str : str.substring(str.length() - len);
}
}
/**
* 从中间截取指定位数
*
* @param str
* @param pos
* @param len
* @return
*/
public static String mid(String str, int pos, int len) {
if (str == null) {
return null;
} else if (len >= 0 && pos <= str.length()) {
if (pos < 0) {
pos = 0;
}
return str.length() <= pos + len ? str.substring(pos) : str.substring(pos, pos + len);
} else {
return "";
}
}
6)truncate方法
/**
* 截断字符串到指定的长度
*
* @param str
* @param maxWidth
* @return 如果字符串的长度小于或等于指定的长度,则返回原始字符串;如果字符串的长度大于指定的长度,则截断字符串并返回截断后的字符串。
*/
public static String truncate(String str, int maxWidth) {
return truncate(str, 0, maxWidth);
}
/**
* 截断字符串到指定的长度,指定起始位置
*
* @param str
* @param offset
* @param maxWidth
* @return
*/
public static String truncate(String str, int offset, int maxWidth) {
if (offset < 0) {
throw new IllegalArgumentException("offset cannot be negative");
} else if (maxWidth < 0) {
throw new IllegalArgumentException("maxWith cannot be negative");
} else if (str == null) {
return null;
} else if (offset > str.length()) {
return "";
} else if (str.length() > maxWidth) {
int ix = Math.min(offset + maxWidth, str.length());
return str.substring(offset, ix);
} else {
return str.substring(offset);
}
}
4.4 替换字符串
1)replace方法
jdk中使用replace,这里使用同样名字,默认替换掉所有匹配项。
/**
* 替换字符串中的指定子字符串
*
* @param str 要替换的字符串
* @param target 要被替换的子字符串
* @param replacement 替换字符串
* @return 替换后的字符串
*/
public static String replace(String str, String target, String replacement) {
if (!isEmpty(str) && !isEmpty(target) && replacement != null) {
return str.replace(target, replacement);
}
return str;
}
2)replaceAll方法
replaceAll方法是基于正则表达式的替换方法,可以替换所有匹配的子字符串。
/**
* 替换字符串中的匹配正则表达式的子字符串
*
* @param str 要替换的字符串
* @param regex 正则表达式
* @param replacement 替换字符串
* @return 替换后的字符串
*/
public static String replaceAll(String str, String regex, String replacement) {
if (!isEmpty(str) && !isEmpty(regex) && replacement != null) {
return str.replaceAll(regex, replacement);
}
return str;
}
4.5.移除字符串
1)remove方法
/**
* 移除字符串
*
* @param str
* @param remove
* @return
*/
public static String remove(String str, String remove) {
return !isEmpty(str) && !isEmpty(remove) ? replace(str, remove, "") : str;
}
/**
* 移除字符
*
* @param str
* @param remove
* @return
*/
public static String remove(String str, char remove) {
if (!isEmpty(str) && str.indexOf(remove) != -1) {
char[] chars = str.toCharArray();
int pos = 0;
for(int i = 0; i < chars.length; ++i) {
if (chars[i] != remove) {
chars[pos++] = chars[i];
}
}
return new String(chars, 0, pos);
} else {
return str;
}
}
示例:
//注意,是第二个参数中所有字符,而不是匹配整个字符串
StringUtils.remove(“queued”, “ue”) = “qd”
2)removeStart 和 removeEnd方法
/**
* 移除开始位置指定字符串
*
* @param str
* @param remove
* @return
*/
public static String removeStart(String str, String remove) {
if (!isEmpty(str) && !isEmpty(remove)) {
return str.startsWith(remove) ? str.substring(remove.length()) : str;
} else {
return str;
}
}
/**
* 移除开始位置指定字符串
*
* @param str
* @param remove
* @return
*/
public static String removeEnd(String str, String remove) {
if (!isEmpty(str) && !isEmpty(remove)) {
return str.endsWith(remove) ? str.substring(0, str.length() - remove.length()) : str;
} else {
return str;
}
}
4.6.覆盖部分字符串
1)overlay方法
典型应用场景,隐藏字符串如证件号码、地址或手机号码中部分字符
/**
* 覆盖部分字符串
*
* @param str
* @param overlay
* @param start
* @param end
* @return
*/
public static String overlay(String str, String overlay, int start, int end) {
if (str == null) {
return null;
} else {
if (overlay == null) {
overlay = "";
}
int len = str.length();
//如果是负数,则表示添加到开始
if (start < 0) {
start = 0;
}
//如果超出字符串自身长度,添加到末尾
if (start > len) {
start = len;
}
//如果是负数,则表示添加到开始
if (end < 0) {
end = 0;
}
//如果超出字符串自身长度,添加到末尾
if (end > len) {
end = len;
}
//判断哪个数字小,哪个就是起始值
if (start > end) {
int temp = start;
start = end;
end = temp;
}
return str.substring(0, start) + overlay + str.substring(end);
}
}
4.7 生成字符串
1)repeat方法
根据指定信息产生字符串
/**
* 生成重复指定次数的字符串
*
* @param str 要重复的字符串
* @param repeatCount 重复次数
* @return 重复指定次数后的字符串
*/
public static String repeat(String str, int repeatCount) {
if (str == null) {
return null;
} else if (repeatCount <= 0) {
return "";
} else {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < repeatCount; i++) {
sb.append(str);
}
return sb.toString();
}
}
/**
* 生成重复指定次数的字符串
*
* @param ch
* @param repeat
* @return
*/
public static String repeat(char ch, int repeat) {
if (repeat <= 0) {
return "";
} else {
char[] buf = new char[repeat];
Arrays.fill(buf, ch);
return new String(buf);
}
}
/**
* 生成重复指定次数的字符串,并使用分隔符进行分隔
*
* @param str
* @param separator
* @param repeat
* @return
*/
public static String repeat(String str, String separator, int repeat) {
if (str != null && separator != null) {
String result = repeat(str + separator, repeat);
return removeEnd(result, separator);
} else {
return repeat(str, repeat);
}
}
示例:
StringUtils.repeat(“a”, 3) = “aaa”
StringUtils.repeat(“ab”, 2) = “abab”StringUtils.repeat(“?”, ", ", 3) = “?, ?, ?”
4.8 前缀和后缀
1)prepend 和 prependIfMissing方法
/**
* 追加前缀
*
* @param str
* @param prefix
* @return
*/
public static String prepend(String str, String prefix) {
return prependIfMissing(str, prefix);
}
/**
* 追加前缀
* (如只有str和prefix两个参数,则是无条件追加,超过两个参数(即prefixes不为空),则是在不匹配prefixes任何情况下才追加)
*
* @param str
* @param prefix
* @param prefixes
* @return
*/
public static String prependIfMissing(String str, String prefix, String... prefixes) {
if (str != null && !isEmpty(prefix) && !startsWith(str, prefix)) {
//在不匹配prefixes任何情况下才追加
if (prefixes != null && Array.getLength(prefixes) > 0) {
String[] prefixArr = prefixes;
int len = prefixes.length;
for(int i = 0; i < len; ++i) {
String p = prefixArr[i];
if (startsWith(str, p)) {
return str;
}
}
}
return prefix.toString() + str;
} else {
return str;
}
}
2)append 和 appendIfMissing方法
/**
* 追加后缀
*
* @param str
* @param suffix
* @return
*/
public static String append(String str, String suffix) {
return appendIfMissing(str, suffix);
}
/**
* 追加后缀
* (如只有str和suffix两个参数,则是无条件追加,超过两个参数,是在不匹配suffixes任何情况下才追加)
*
* @param str
* @param suffix
* @param suffixes
* @return
*/
public static String appendIfMissing(String str, String suffix, String... suffixes) {
if (str != null && !isEmpty(suffix) && !endsWith(str, suffix)) {
//在不匹配suffixes任何情况下才追加
if (suffixes != null && Array.getLength(suffixes) > 0) {
String[] suffixArr = suffixes;
int len = suffixes.length;
for(int i = 0; i < len; ++i) {
String s = suffixArr[i];
if (endsWith(str, s)) {
return str;
}
}
}
return str + suffix.toString();
} else {
return str;
}
}
3)wrap 和 wrapIfMissing方法
/**
* 无条件同时增加前缀和后缀
*
* @param str
* @param wrapWith
* @return
*/
public static String wrap(String str, char wrapWith) {
return !isEmpty(str) && wrapWith != 0 ? wrapWith + str + wrapWith : str;
}
/**
* 无条件同时增加前缀和后缀
*
* @param str
* @param wrapWith
* @return
*/
public static String wrap(String str, String wrapWith) {
return !isEmpty(str) && !isEmpty(wrapWith) ? wrapWith.concat(str).concat(wrapWith) : str;
}
/**
* 有条件同时增加前缀和后缀
*
* @param str
* @param wrapWith
* @return
*/
public static String wrapIfMissing(String str, char wrapWith) {
if (!isEmpty(str) && wrapWith != 0) {
boolean wrapStart = str.charAt(0) != wrapWith;
boolean wrapEnd = str.charAt(str.length() - 1) != wrapWith;
if (!wrapStart && !wrapEnd) {
return str;
} else {
StringBuilder builder = new StringBuilder(str.length() + 2);
if (wrapStart) {
builder.append(wrapWith);
}
builder.append(str);
if (wrapEnd) {
builder.append(wrapWith);
}
return builder.toString();
}
} else {
return str;
}
}
/**
* 有条件同时增加前缀和后缀
*
* @param str
* @param wrapWith
* @return
*/
public static String wrapIfMissing(String str, String wrapWith) {
if (!isEmpty(str) && !isEmpty(wrapWith)) {
boolean wrapStart = !str.startsWith(wrapWith);
boolean wrapEnd = !str.endsWith(wrapWith);
if (!wrapStart && !wrapEnd) {
return str;
} else {
StringBuilder builder = new StringBuilder(str.length() + wrapWith.length() + wrapWith.length());
if (wrapStart) {
builder.append(wrapWith);
}
builder.append(str);
if (wrapEnd) {
builder.append(wrapWith);
}
return builder.toString();
}
} else {
return str;
}
}
4)unwrap方法
/**
* 去除前缀和后缀
*
* @param str
* @param wrapChar
* @return
*/
public static String unwrap(String str, char wrapChar) {
if (!isEmpty(str) && wrapChar != 0 && str.length() != 1) {
if (str.charAt(0) == wrapChar && str.charAt(str.length() - 1) == wrapChar) {
int endIndex = str.length() - 1;
return str.substring(1, endIndex);
} else {
return str;
}
} else {
return str;
}
}
/**
* 去除前缀和后缀
*
* @param str
* @param wrapToken
* @return
*/
public static String unwrap(String str, String wrapToken) {
if (!isEmpty(str) && !isEmpty(wrapToken) && str.length() >= 2 * wrapToken.length()) {
if (startsWith(str, wrapToken) && endsWith(str, wrapToken)) {
int startIndex = str.indexOf(wrapToken);
int endIndex = str.lastIndexOf(wrapToken);
int wrapLength = wrapToken.length();
if (startIndex != -1 && endIndex != -1) {
return str.substring(startIndex + wrapLength, endIndex);
}
}
return str;
} else {
return str;
}
}
4.9 添加双引号
1)quote 和 quoteIfString 方法
/**
* 在字符串两端添加双引号
*
* @param str
* @return
*/
public static String quote(String str) {
return str != null ? "'" + str + "'" : null;
}
/**
* 在字符串两端添加双引号
*
* @param obj
* @return
*/
public static Object quoteIfString(Object obj) {
return obj instanceof String ? quote((String)obj) : obj;
}
示例
StringUtils.quote("example"); // "\"example\""
5.字符串转换
字符串内容意义不变,形式变化
5.1 大小写转换
1)upperCase 和 lowerCase方法
转换字符串至大写或小写状态
/**
* 将字符串转换为大写
*
* @param str 要转换的字符串
* @return 转换为大写后的字符串
*/
public static String upperCase(String str) {
return str == null ? null : str.toUpperCase();
}
/**
* 将字符串转换为大写
*
* @param str 要转换的字符串
* @param locale
* @return 转换为大写后的字符串
*/
public static String upperCase(String str, Locale locale) {
locale = locale != null ? locale : Locale.getDefault();
return str == null ? null : str.toUpperCase(locale);
}
/**
* 将字符串转换为小写
*
* @param str
* @return
*/
public static String lowerCase(String str) {
return str == null ? null : str.toLowerCase();
}
/**
* 将字符串转换为小写
*
* @param str
* @param locale
* @return
*/
public static String lowerCase(String str, Locale locale) {
locale = locale != null ? locale : Locale.getDefault();
return str == null ? null : str.toLowerCase(locale);
}
2)capitalize 和 uncapitalize方法
/**
* 将字符串转换为首字母大写
*
* @param str 要转换的字符串
* @return 首字母大写的字符串
*/
public static String capitalize(String str) {
if (isEmpty(str)) {
return str;
}
return Character.toUpperCase(str.charAt(0)) + str.substring(1);
}
/**
* 将字符串转换为首字母小写
*
* @param str 要转换的字符串
* @return 首字母小写的字符串
*/
public static String uncapitalize(String str) {
if (isEmpty(str)) {
return str;
}
return Character.toLowerCase(str.charAt(0)) + str.substring(1);
}
3)swapCase方法
/**
* 大小写交换,即大写变小写,小写变大写
*
* @param str 要转换的字符串
* @return 返回大小写字母转换后生成的新字符串
*/
public static String swapCase(String str) {
if (isEmpty(str)) {
return str;
} else {
char[] charArray = str.toCharArray();
for (int i = 0; i < charArray.length; i++) {
if (Character.isUpperCase(charArray[i])) {
charArray[i] = Character.toLowerCase(charArray[i]);
} else if (Character.isLowerCase(charArray[i])) {
charArray[i] = Character.toUpperCase(charArray[i]);
}
}
return new String(charArray);
}
}
5.2 命名格式转换
1)camelCase方法
将下划线命名法的字符串转换为驼峰命名法(首字母小写)
/**
* 将下划线命名法的字符串转换为驼峰命名法(首字母小写)
* 例如: "hello_world" -> "helloWorld"
*
* @param str 要转换的字符串
* @return 转换后的字符串
*/
public static String camelCase(String str) {
if (isEmpty(str)) {
return str;
}
StringBuilder sb = new StringBuilder();
String[] words = str.split("_");
sb.append(words[0]);
for (int i = 1; i < words.length; i++) {
sb.append(capitalize(words[i]));
}
return sb.toString();
}
2)pascalCase方法
将下划线命名法的字符串转换为帕斯卡命名法(首字母大写)
/**
* 将下划线命名法的字符串转换为帕斯卡命名法(首字母大写)
* 例如: "hello_world" -> "HelloWorld"
*
* @param str 要转换的字符串
* @return 转换后的字符串
*/
public static String pascalCase(String str) {
if (isEmpty(str)) {
return str;
}
StringBuilder sb = new StringBuilder();
String[] words = str.split("_");
for (int i = 0; i < words.length; i++) {
sb.append(capitalize(words[i]));
}
return sb.toString();
}
3)pascalCase方法
将字符串转换为下划线命名法(小写字母,单词间用下划线分隔)
/**
* 将字符串转换为下划线命名法(小写字母,单词间用下划线分隔)
* 例如: "HelloWorld" -> "hello_world"
*
* @param str 要转换的字符串
* @return 转换后的字符串
*/
public static String snakeCase(String str) {
if (isEmpty(str)) {
return str;
}
StringBuilder sb = new StringBuilder();
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
if (Character.isUpperCase(c)) {
if (i > 0) {
sb.append('_');
}
sb.append(Character.toLowerCase(c));
} else {
sb.append(c);
}
}
return sb.toString();
}
5.3 字符串缩略
1)abbreviate方法
将字符串缩减为指定宽度,注意,maxWidth必须>=4,否则抛异常;
如果字符长度小于maxWidth,直接返回该字符串,否则缩减效果为 substring(str, 0, max-3) + “…”
/**
* 将指定位置后面的字符串以省略号显示
*
* @param str
* @param maxWidth
* @return
*/
public static String abbreviate(String str, int maxWidth) {
return abbreviate(str, "...", 0, maxWidth);
}
/**
* 指定偏移量,将指定位置后面的字符串以省略号显示
*
* @param str
* @param offset
* @param maxWidth
* @return
*/
public static String abbreviate(String str, int offset, int maxWidth) {
return abbreviate(str, "...", offset, maxWidth);
}
/**
* 将指定位置后面的字符串以指定字符显示
*
* @param str
* @param abbrevMarker
* @param maxWidth
* @return
*/
public static String abbreviate(String str, String abbrevMarker, int maxWidth) {
return abbreviate(str, abbrevMarker, 0, maxWidth);
}
/**
* 指定偏移量,将指定位置后面的字符串以指定字符显示
*
* @param str
* @param abbrevMarker
* @param offset
* @param maxWidth
* @return
*/
public static String abbreviate(String str, String abbrevMarker, int offset, int maxWidth) {
if (isNotEmpty(str) && "".equals(abbrevMarker) && maxWidth > 0) {
return substring(str, 0, maxWidth);
} else if (isEmpty(str) || isEmpty(abbrevMarker)) {
return str;
} else {
int abbrevMarkerLength = abbrevMarker.length();
int minAbbrevWidth = abbrevMarkerLength + 1;
int minAbbrevWidthOffset = abbrevMarkerLength + abbrevMarkerLength + 1;
if (maxWidth < minAbbrevWidth) {
throw new IllegalArgumentException(String.format("Minimum abbreviation width is %d", minAbbrevWidth));
} else {
int strLen = str.length();
if (strLen <= maxWidth) {
return str;
} else {
if (offset > strLen) {
offset = strLen;
}
if (strLen - offset < maxWidth - abbrevMarkerLength) {
offset = strLen - (maxWidth - abbrevMarkerLength);
}
if (offset <= abbrevMarkerLength + 1) {
return str.substring(0, maxWidth - abbrevMarkerLength) + abbrevMarker;
} else if (maxWidth < minAbbrevWidthOffset) {
throw new IllegalArgumentException(String.format("Minimum abbreviation width with offset is %d", minAbbrevWidthOffset));
} else {
return offset + maxWidth - abbrevMarkerLength < strLen ? abbrevMarker + abbreviate(str.substring(offset), abbrevMarker, maxWidth - abbrevMarkerLength) : abbrevMarker + str.substring(strLen - (maxWidth - abbrevMarkerLength));
}
}
}
}
}
/**
* 字符串缩略
*
* @param str
* @param middle
* @param length
* @return
*/
public static String abbreviateMiddle(String str, String middle, int length) {
if (isNotEmpty(str) && isNotEmpty(middle) && length < str.length() && length >= middle.length() + 2) {
int targetSting = length - middle.length();
int startOffset = targetSting / 2 + targetSting % 2;
int endOffset = str.length() - targetSting / 2;
return str.substring(0, startOffset) + middle + str.substring(endOffset);
} else {
return str;
}
}
5.4 补齐字符串
自动补齐至指定宽度,可指定字符,如不指定,默认补空格,有三个,center、leftPad和rightPad
使用场景:
显示时补充数据宽度一致使其对齐,更美观
单据流水号,宽度固定,左侧补0
1)leftPad方法
/**
* 左侧补齐,自动补齐至指定宽,使用空格补齐
*
* @param str 原始字符串
* @param size 字符串的长度
* @return
*/
public static String leftPad(String str, int size) {
return leftPad(str, size, ' ');
}
/**
* 左侧补齐,自动补齐至指定宽度,可指定字符
*
* @param str 原始字符串
* @param size 字符串的长度
* @param padChar 补充的字符
* @return
*/
public static String leftPad(String str, int size, char padChar) {
if (str == null) {
return null;
} else {
int pads = size - str.length();
if (pads <= 0) {
return str;
} else {
return pads > 8192 ? leftPad(str, size, String.valueOf(padChar)) : repeat(padChar, pads).concat(str);
}
}
}
/**
* 左侧补齐,自动补齐至指定宽度,可指定字符
*
* @param str 原始字符串
* @param size 字符串的长度
* @param padStr 补充的字符串
* @return
*/
public static String leftPad(String str, int size, String padStr) {
if (str == null) {
return null;
} else {
if (isEmpty(padStr)) {
padStr = " ";
}
int padLen = padStr.length();
int strLen = str.length();
int pads = size - strLen;
if (pads <= 0) {
return str;
} else if (padLen == 1 && pads <= 8192) {
return leftPad(str, size, padStr.charAt(0));
} else if (pads == padLen) {
return padStr.concat(str);
} else if (pads < padLen) {
return padStr.substring(0, pads).concat(str);
} else {
char[] padding = new char[pads];
char[] padChars = padStr.toCharArray();
for(int i = 0; i < pads; ++i) {
padding[i] = padChars[i % padLen];
}
return (new String(padding)).concat(str);
}
}
}
2)rightPad方法
/**
* 右侧补齐,自动补齐至指定宽,使用空格补齐
*
* @param str 原始字符串
* @param size 字符串的长度
* @return
*/
public static String rightPad(String str, int size) {
return rightPad(str, size, ' ');
}
/**
* 右侧补齐,自动补齐至指定宽度,可指定字符
*
* @param str 原始字符串
* @param size 字符串的长度
* @param padChar 补充的字符
* @return
*/
public static String rightPad(String str, int size, char padChar) {
if (str == null) {
return null;
} else {
int pads = size - str.length();
if (pads <= 0) {
return str;
} else {
return pads > 8192 ? rightPad(str, size, String.valueOf(padChar)) : str.concat(repeat(padChar, pads));
}
}
}
/**
* 右侧补齐,自动补齐至指定宽度,可指定字符
*
* @param str 原始字符串
* @param size 字符串的长度
* @param padStr 补充的字符串
* @return
*/
public static String rightPad(String str, int size, String padStr) {
if (str == null) {
return null;
} else {
if (isEmpty(padStr)) {
padStr = " ";
}
int padLen = padStr.length();
int strLen = str.length();
int pads = size - strLen;
if (pads <= 0) {
return str;
} else if (padLen == 1 && pads <= 8192) {
return rightPad(str, size, padStr.charAt(0));
} else if (pads == padLen) {
return str.concat(padStr);
} else if (pads < padLen) {
return str.concat(padStr.substring(0, pads));
} else {
char[] padding = new char[pads];
char[] padChars = padStr.toCharArray();
for(int i = 0; i < pads; ++i) {
padding[i] = padChars[i % padLen];
}
return str.concat(new String(padding));
}
}
}
3)center方法
/**
* 中间填充
*
* @param str 原始字符串
* @param size 字符串的长度
* @return
*/
public static String center(String str, int size) {
return center(str, size, ' ');
}
/**
* 中间填充
*
* @param str 原始字符串
* @param size 字符串的长度
* @param padChar 补充的字符
* @return
*/
public static String center(String str, int size, char padChar) {
if (str != null && size > 0) {
int strLen = str.length();
int pads = size - strLen;
if (pads <= 0) {
return str;
} else {
str = leftPad(str, strLen + pads / 2, padChar);
str = rightPad(str, size, padChar);
return str;
}
} else {
return str;
}
}
/**
* 中间填充
*
* @param str 原始字符串
* @param size 字符串的长度
* @param padStr 补充的字符串
* @return
*/
public static String center(String str, int size, String padStr) {
if (str != null && size > 0) {
if (isEmpty(padStr)) {
padStr = " ";
}
int strLen = str.length();
int pads = size - strLen;
if (pads <= 0) {
return str;
} else {
str = leftPad(str, strLen + pads / 2, padStr);
str = rightPad(str, size, padStr);
return str;
}
} else {
return str;
}
}
5.5 旋转字符串
1)rotate方法
/**
* 旋转(循环移位)字符串
*
* @param str 原始字符串
* @param shift 大于0则右旋,小于0则左旋
* @return
*/
public static String rotate(String str, int shift) {
if (str == null) {
return null;
} else {
int strLen = str.length();
if (shift != 0 && strLen != 0 && shift % strLen != 0) {
StringBuilder builder = new StringBuilder(strLen);
int offset = -(shift % strLen);
builder.append(substring(str, offset));
builder.append(substring(str, 0, offset));
return builder.toString();
} else {
return str;
}
}
}
示例:
StringUtils.rotate("abcdefg", 2) = "fgabcde"
StringUtils.rotate("abcdefg", -2) = "cdefgab"
2)reverse方法
/**
* 将字符串反转,完全颠倒字符串顺序
*
* @param str 要反转的字符串
* @return 反转后的字符串
*/
public static String reverse(String str) {
return str == null ? null : (new StringBuilder(str)).reverse().toString();
}
3)reverseDelimited方法
/**
* 颠倒字符串顺序,以间隔符为单位进行,单个元素内部不颠倒位置
*
* @param str
* @param separatorChar
* @return
*/
public static String reverseDelimited(String str, String separatorChar) {
if (str == null) {
return null;
} else {
String[] strs = split(str, separatorChar);
//进行数组元素顺序反转
if (strs != null) {
int i = 0;
for(int j = strs.length - 1; j > i; ++i) {
String tmp = strs[j];
strs[j] = strs[i];
strs[i] = tmp;
--j;
}
}
return join((Object[])strs, separatorChar);
}
}
示例:
StringUtils.reverseDelimited("a.bc.d",'.')="d.bc.a"
5.6 编码转换
1)toEncodedString方法
将字节数组转换为指定编码的字符串。应用场景:系统间交互时,字符编码不一致,如对方传递的参数编码为GB2312,我方编码为UTF-8,可通过该方法进行转换。
/**
* 将字节数组转换为指定编码的字符串
*
* @param bytes
* @param charset
* @return
*/
public static String toEncodedString(byte[] bytes, Charset charset) {
charset = charset == null ? Charset.defaultCharset() : charset;
return new String(bytes, charset);
}
2)toCodePoints方法
将字节数组转换为Unicode代码点数组。
/**
* 将字符串转换为Unicode代码点数组
*
* @param cs
* @return
*/
public static int[] toCodePoints(CharSequence cs) {
if (cs == null) {
return null;
} else if (cs.length() == 0) {
return new int[0];
} else {
String s = cs.toString();
int[] result = new int[s.codePointCount(0, s.length())];
int index = 0;
for(int i = 0; i < result.length; ++i) {
result[i] = s.codePointAt(index);
index += Character.charCount(result[i]);
}
return result;
}
}
6 文件路径名称相关
获取和操作文件路径,文件名和扩展名等
6.1 文件名
1)getFilename方法
/**
* 获取文件名
*
* @param path
* @return
*/
public static String getFilename(String path) {
if (path == null) {
return null;
} else {
int separatorIndex = path.lastIndexOf("/");
return separatorIndex != -1 ? path.substring(separatorIndex + 1) : path;
}
}
6.2 文件扩展名
1)getFilenameExtension方法
/**
* 获取文件扩展名
*
* @param path
* @return
*/
public static String getFilenameExtension(String path) {
if (path == null) {
return null;
} else {
int extIndex = path.lastIndexOf(46);
if (extIndex == -1) {
return null;
} else {
int folderIndex = path.lastIndexOf("/");
return folderIndex > extIndex ? null : path.substring(extIndex + 1);
}
}
}
2)stripFilenameExtension方法
/**
* 舍去文件扩展名
*
* @param path
* @return
*/
public static String stripFilenameExtension(String path) {
int extIndex = path.lastIndexOf(46);
if (extIndex == -1) {
return path;
} else {
int folderIndex = path.lastIndexOf("/");
return folderIndex > extIndex ? path : path.substring(0, extIndex);
}
}
7 其他
难以归类的一些功能性方法
7.1 获取字符串长度
1)length方法
/**
* 获取字符串的长度
*
* @param str 要获取长度的字符串
* @return 字符串的长度
*/
public static int length(String str) {
return str == null ? 0 : str.length();
}
2)codePointCount方法
/**
* 获取字符串的长度(考虑Unicode扩展字符)
*
* @param str 要获取长度的字符串
* @return 字符串的长度
*/
public static int codePointCount(String str) {
if (isEmpty(str)) {
return 0;
}
return str.codePointCount(0, str.length());
}
7.2.计算匹配次数
1)countMatches方法
/**
* 计算匹配次数
*
* @param str
* @param ch
* @return
*/
public static int countMatches(String str, char ch) {
if (isEmpty(str)) {
return 0;
} else {
int count = 0;
for(int i = 0; i < str.length(); ++i) {
if (ch == str.charAt(i)) {
++count;
}
}
return count;
}
}
/**
* 计算匹配次数
*
* @param str
* @param sub
* @return
*/
public static int countMatches(String str, String sub) {
if (!isEmpty(str) && !isEmpty(sub)) {
int count = 0;
for(int idx = 0; (idx = indexOf(str, sub, idx)) != -1; idx += sub.length()) {
++count;
}
return count;
} else {
return 0;
}
}
7.3 默认值处理
1)defaultString方法
/**
* 获取默认字符串
*
* @param str
* @return null及空格将会返回"",其他情况返回原始字符串
*/
public static String defaultString(String str) {
return defaultString(str, "");
}
/**
* 获取默认字符串
*
* @param str
* @param defaultStr
* @return 第一个参数为null及空格将会返回第二个参数指定值,其他情况返回原始字符串
*/
public static String defaultString(String str, String defaultStr) {
return str == null ? defaultStr : str;
}
2)defaultIfBlank 和 defaultIfEmpty方法
/**
* 如果为空白,返回指定值
*
* @param str
* @param defaultStr
* @return
*/
public static String defaultIfBlank(String str, String defaultStr) {
return isBlank(str) ? defaultStr : str;
}
/**
* 如果为空,返回指定值
*
* @param str
* @param defaultStr
* @return
*/
public static String defaultIfEmpty(String str, String defaultStr) {
return isEmpty(str) ? defaultStr : str;
}
3)firstNonBlank 和 firstNonEmpty方法
/**
* 获取数组中第一个不为空白的元素
*
* @param values
* @return
*/
@SafeVarargs
public static String firstNonBlank(String... values) {
if (values != null) {
String[] valArr = values;
int len = values.length;
for(int i = 0; i < len; ++i) {
String val = valArr[i];
if (isNotBlank(val)) {
return val;
}
}
}
return null;
}
/**
* 获取数组中第一个不为空的元素
*
* @param values
* @return
*/
@SafeVarargs
public static String firstNonEmpty(String... values) {
if (values != null) {
String[] valArr = values;
int len = values.length;
for(int i = 0; i < len; ++i) {
String val = valArr[i];
if (isNotEmpty(val)) {
return val;
}
}
}
return null;
}
7.4.字符串差异
1)indexOfDifference方法
/**
* 获取字符串差异的索引位置
*
* @param str1
* @param str2
* @return
*/
public static int indexOfDifference(String str1, String str2) {
if (str1 == str2) {
return -1;
} else if (str1 != null && str2 != null) {
int i;
for(i = 0; i < str1.length() && i < str2.length() && str1.charAt(i) == str2.charAt(i); ++i) {
}
return i >= str2.length() && i >= str1.length() ? -1 : i;
} else {
return 0;
}
}
2)difference方法
/**
* 获取字符串差异部分
*
* @param str1
* @param str2
* @return
*/
public static String difference(String str1, String str2) {
if (str1 == null) {
return str2;
} else if (str2 == null) {
return str1;
} else {
int at = indexOfDifference(str1, str2);
return at == -1 ? "" : str2.substring(at);
}
}
7.5 取字符串相同前缀
1)getCommonPrefix方法
/**
* 获取字符串相同前缀
*
* @param str1
* @param str2
* @return
*/
public static String getCommonPrefix(String str1, String str2) {
if (isEmpty(str1) || isEmpty(str2)) {
return "";
} else {
int smallestIndexOfDiff = indexOfDifference(str1, str2);
if (smallestIndexOfDiff == -1) {
return str1 == null ? "" : str1;
} else {
return smallestIndexOfDiff == 0 ? "" : str1.substring(0, smallestIndexOfDiff);
}
}
}
示例:
StringUtils.getCommonPrefix(new String[] {"abcde", "abxyz"}) = "ab"