Sprint源码学习之StringUtils类

来源:互联网 发布:seo标签优化 编辑:程序博客网 时间:2024/06/07 13:51
   /* * To change this template, choose Tools | Templates * and open the template in the editor. */package arthurv.java.spring.learn;import java.util.ArrayList;import java.util.Arrays;import java.util.Collection;import java.util.Collections;import java.util.Enumeration;import java.util.Iterator;import java.util.LinkedList;import java.util.List;import java.util.Locale;import java.util.Properties;import java.util.Set;import java.util.StringTokenizer;import java.util.TreeSet;/** */public abstract class StringUtils {private static final String FOLDER_SEPARATOR = "/";private static final String WINDOWS_FOLDER_SEPARATOR = "\\";private static final String TOP_PATH = "..";private static final String CURRENT_PATH = ".";private static final char EXTENSION_SEPARATOR = '.';//---------------------------------------------------------------------// General convenience methods for working with Strings//---------------------------------------------------------------------        //判断str是否为空值public static boolean hasLength(CharSequence str) {return (str != null && str.length() > 0);}/**         * 判断字符串是否有长度         * 注意CharSequence是String类的上层接口         * @param str         * @return          */public static boolean hasLength(String str) {return hasLength((CharSequence) str);}/**         * 判断CharSequence是否有实际内容,空格不算 * <p><pre> * StringUtils.hasText(null) = false * StringUtils.hasText("") = false * StringUtils.hasText(" ") = false * StringUtils.hasText("12345") = true * StringUtils.hasText(" 12345 ") = true */public static boolean hasText(CharSequence str) {                //如果str为空,返回falseif (!hasLength(str)) {return false;}                //获取str的长度int strLen = str.length();                //循环遍历strfor (int i = 0; i < strLen; i++) {                        //如果在0到strlen之间,有一个不是空格,说明有内容,返回trueif (!Character.isWhitespace(str.charAt(i))) {return true;}}return false;}/**         * 判断str是否是实际内容,纯空格组成的str返回false */public static boolean hasText(String str) {return hasText((CharSequence) str);}/**         *检测CharSequence是否有空白字符 */public static boolean containsWhitespace(CharSequence str) {                //如果长度为0,则返回falseif (!hasLength(str)) {return false;}int strLen = str.length();                //循环遍历strfor (int i = 0; i < strLen; i++) {                       //如果在0到strLen之间有空白符,则返回trueif (Character.isWhitespace(str.charAt(i))) {return true;}}return false;}/**         *判断给定的字符串str是否含有空白符 */public static boolean containsWhitespace(String str) {return containsWhitespace((CharSequence) str);}/**         * 去掉str开头和结尾的空白符 */public static String trimWhitespace(String str) {                //如果没有长度,则放回strif (!hasLength(str)) {return str;}                                StringBuilder sb = new StringBuilder(str);                //如果sb.charAt(0)是空白符的话,删除该空白符while (sb.length() > 0 && Character.isWhitespace(sb.charAt(0))) {sb.deleteCharAt(0);}                //如果末尾是空白符的话,也删除该空白符while (sb.length() > 0 && Character.isWhitespace(sb.charAt(sb.length() - 1))) {sb.deleteCharAt(sb.length() - 1);}                //返回去掉开头结尾空白符之后的字符串return sb.toString();}/**         *删除给定的字符串中所有的空白符 */public static String trimAllWhitespace(String str) {                //如果str没有长度,返回strif (!hasLength(str)) {return str;}StringBuilder sb = new StringBuilder(str);int index = 0;                //循环遍历sbwhile (sb.length() > index) {                        //如果当前位置index为空白符,则删除之if (Character.isWhitespace(sb.charAt(index))) {sb.deleteCharAt(index);}else {index++;}}                //返回去掉空白符之后的字符串return sb.toString();}/**         *删除掉str的开头的空白符,如果有的话 */public static String trimLeadingWhitespace(String str) {               //如果str的长度为0,返回strif (!hasLength(str)) {return str;}StringBuilder sb = new StringBuilder(str);                //如果开头有字符串,则删除之while (sb.length() > 0 && Character.isWhitespace(sb.charAt(0))) {sb.deleteCharAt(0);}                //返回删除开头空白符的字符串return sb.toString();}/** * 删除str结尾的空白符,如果结尾是空白符的话 */public static String trimTrailingWhitespace(String str) {               //如果str的长度为0,返回strif (!hasLength(str)) {return str;}StringBuilder sb = new StringBuilder(str);                //如结尾头有字符串,则删除之while (sb.length() > 0 && Character.isWhitespace(sb.charAt(sb.length() - 1))) {sb.deleteCharAt(sb.length() - 1);}                //返回删除开头空白符的字符串return sb.toString();}/**          *删除str中开头是字符是给定字符的那个字符 */public static String trimLeadingCharacter(String str, char leadingCharacter) {               //如果str的长度为0,返回strif (!hasLength(str)) {return str;}StringBuilder sb = new StringBuilder(str);                //判断sb的开头是否==leadingCharacter,若是就删除,否则什么也不做while (sb.length() > 0 && sb.charAt(0) == leadingCharacter) {sb.deleteCharAt(0);}return sb.toString();}/**         *删除结尾等于trailingCharacter的那个字符 */public static String trimTrailingCharacter(String str, char trailingCharacter) {                 //如果str的长度为0,返回strif (!hasLength(str)) {return str;}StringBuilder sb = new StringBuilder(str);                 //判断sb的开头是否==leadingCharacter,若是就删除,否则什么也不做while (sb.length() > 0 && sb.charAt(sb.length() - 1) == trailingCharacter) {sb.deleteCharAt(sb.length() - 1);}return sb.toString();}/** *检测str的前缀是否是prefix,大小写不敏感 */public static boolean startsWithIgnoreCase(String str, String prefix) {if (str == null || prefix == null) {return false;}                //如果是则返回trueif (str.startsWith(prefix)) {return true;}                //如果str小于前缀,则返回falseif (str.length() < prefix.length()) {return false;}                //设定大小写不明感                //把str的前面长度等于prefix的字符变小写String lcStr = str.substring(0, prefix.length()).toLowerCase();                //把prefix变小写String lcPrefix = prefix.toLowerCase();                //判断return lcStr.equals(lcPrefix);}/** *检测str的后缀是否是prefix,大小写不敏感 */public static boolean endsWithIgnoreCase(String str, String suffix) {if (str == null || suffix == null) {return false;}                //如果后缀是suffix,返回trueif (str.endsWith(suffix)) {return true;}if (str.length() < suffix.length()) {return false;}               //设定大小写不敏感String lcStr = str.substring(str.length() - suffix.length()).toLowerCase();String lcSuffix = suffix.toLowerCase();return lcStr.equals(lcSuffix);}/**         * 判断给定的str中是否有在位置index处存在子序列subString */public static boolean substringMatch(CharSequence str, int index, CharSequence substring) {for (int j = 0; j < substring.length(); j++) {int i = index + j;                        //如果i>=str.length说明str字符串自index到最后的长度小于subString                        //str.charAt(i) != substring.charAt(j),如果当前j位置字符和str中i位置字符不相等if (i >= str.length() || str.charAt(i) != substring.charAt(j)) {return false;}}return true;}/**         *检测str中出现sub子字符串的个数. */public static int countOccurrencesOf(String str, String sub) {               //边界处理if (str == null || sub == null || str.length() == 0 || sub.length() == 0) {return 0;}                //计数器int count = 0;                //记录当前位置int pos = 0;int idx;                //indexOf(String str,int fromIndex)str - 要搜索的子字符串。                //fromIndex - 开始搜索的索引位置                //如果含有此sub,则计数器+1while ((idx = str.indexOf(sub, pos)) != -1) {++count;                        //下一个开始比较的位置pos = idx + sub.length();}                //返回sub出现的个数return count;}/**         * 用newPattern来替换inString中的oldPattern */public static String replace(String inString, String oldPattern, String newPattern) {               //边界处理if (!hasLength(inString) || !hasLength(oldPattern) || newPattern == null) {return inString;}                StringBuilder sb = new StringBuilder();int pos = 0;                //返回oldPattern在inString的位置索引int index = inString.indexOf(oldPattern);                //记录oldPattern的长度int patLen = oldPattern.length();while (index >= 0) {                        //保存index之前的inString子串sb.append(inString.substring(pos, index));                        //拼接新的字符(串)sb.append(newPattern);pos = index + patLen;                        //检测pos之后是否还有oldPattern,如果有继续替换index = inString.indexOf(oldPattern, pos);}                //拼接pos之后的字符串sb.append(inString.substring(pos));// remember to append any characters to the right of a matchreturn sb.toString();}/**         *删除inString中符合pattern要求的字符(串)         * 实现方法是:把inString中符合pattern的字符(串)替换成“”从而实现删除 */public static String delete(String inString, String pattern) {return replace(inString, pattern, "");}/**         * 到此可以发先StringBuilder的强大作用         * 删除inString中在charsToDelete中存在的字符         * 例如         * inString = "abddfkjfd";         * charsToDelete = "cdjf";         * 则处理后的inString = "abk" */public static String deleteAny(String inString, String charsToDelete) {                //边界处理if (!hasLength(inString) || !hasLength(charsToDelete)) {return inString;}                //字符构造器StringBuilder sb = new StringBuilder();                //循环遍历inString,判断每个字符是否在charsToDelete中for (int i = 0; i < inString.length(); i++) {                       //获取当前位置i的字符cchar c = inString.charAt(i);                        //如果charsToDelete中不包含c,则拼接到sb中if (charsToDelete.indexOf(c) == -1) {sb.append(c);}}                //返回处理过的字符串return sb.toString();}//---------------------------------------------------------------------// Convenience methods for working with formatted Strings//---------------------------------------------------------------------/** * 用单引号把非空的str括起来,例如str == "hello" 那么返回的将是‘hello’ */public static String quote(String str) {return (str != null ? "'" + str + "'" : null);}/** * 如果给定的对象是String类型,则调用quote方法处理,否则什么都不做原样返回 */public static Object quoteIfString(Object obj) {return (obj instanceof String ? quote((String) obj) : obj);}/** * Unqualify a string qualified by a '.' dot character. For example, * "this.name.is.qualified", returns "qualified". * @param qualifiedName the qualified name */public static String unqualify(String qualifiedName) {return unqualify(qualifiedName, '.');}/** * 获取给定的字符串中,最后一个满足分隔符separator之后字符串,         * 例如 qualifiedName = "this:name:is:qualified"         *     separator = ':'         * 那么处理过后的字符串就是 qualified */public static String unqualify(String qualifiedName, char separator) {return qualifiedName.substring(qualifiedName.lastIndexOf(separator) + 1);}/**         *设置首字母为大写 */public static String capitalize(String str) {return changeFirstCharacterCase(str, true);}/**         *设置str首字母为小写 */public static String uncapitalize(String str) {return changeFirstCharacterCase(str, false);}private static String changeFirstCharacterCase(String str, boolean capitalize) {if (str == null || str.length() == 0) {return str;}StringBuilder sb = new StringBuilder(str.length());if (capitalize) {//如果首字母要求大写的话sb.append(Character.toUpperCase(str.charAt(0)));}else {   //否则首字母设置为小写sb.append(Character.toLowerCase(str.charAt(0)));}                //拼接首字母剩下的字符串sb.append(str.substring(1));return sb.toString();}/** * 获得给用路径path中的文件名 * 例如 "mypath/myfile.txt" -> "myfile.txt". */public static String getFilename(String path) {                //边界处理if (path == null) {return null;}                //获得path中最后一个文件分隔符‘/’的位置int separatorIndex = path.lastIndexOf(FOLDER_SEPARATOR);                //如果没有分隔符,说明给定的就是文件名,直接返回即可,否则返回分隔符剩下的字符return (separatorIndex != -1 ? path.substring(separatorIndex + 1) : path);}/** *获得文件名的扩展名,也就是格式 * e.g. "mypath/myfile.txt" -> "txt". */public static String getFilenameExtension(String path) {                //边界处理if (path == null) {return null;}                //获得最后一个‘.’的位置int extIndex = path.lastIndexOf(EXTENSION_SEPARATOR);if (extIndex == -1) {return null;}                //找到最后一个文件分隔符‘/’的位置int folderIndex = path.lastIndexOf(FOLDER_SEPARATOR);                //如果folderIndex在extIndex的右边,返回nullif (folderIndex > extIndex) {return null;}                //返回‘.’之后的子字符串return path.substring(extIndex + 1);}/** *过滤掉文件的扩展名 * 例如. "mypath/myfile.txt" -> "mypath/myfile". */public static String stripFilenameExtension(String path) {                //边界处理if (path == null) {return null;}                //获得最后一个‘.’的位置int extIndex = path.lastIndexOf(EXTENSION_SEPARATOR);if (extIndex == -1) {return path;}                //找到最后一个文件分隔符‘/’的位置int folderIndex = path.lastIndexOf(FOLDER_SEPARATOR);                 //如果folderIndex在extIndex的右边,path是文件路径,没有扩展名可言,直接原样返回if (folderIndex > extIndex) {return path;}                //返回滤掉扩展名之后的子字符串return path.substring(0, extIndex);}/**         * 该方法的作用如下         * 如果path = "/hello/world/ relativePtah = "java"         * 经过处理后返回 /hello/world/java         * 如果path = "helloworld" 那么处理后返回java         * 这个方法少了空值判断,个人觉得加上严谨些 */public static String applyRelativePath(String path, String relativePath) {               //找到最后个文件分隔符的位置int separatorIndex = path.lastIndexOf(FOLDER_SEPARATOR);if (separatorIndex != -1) {//如果有文件分隔符                       //获得从0到最后一个分隔符之前的子字符串String newPath = path.substring(0, separatorIndex);                        //如果relativePath不是以文件分隔符开头if (!relativePath.startsWith(FOLDER_SEPARATOR)) {                               //把newPath后面追加一个/newPath += FOLDER_SEPARATOR;}                        //返回newPath+relativePathreturn newPath + relativePath;}else {//如果没有,就返回relativePathreturn relativePath;}}//end/** * Normalize the path by suppressing sequences like "path/.." and * inner simple dots. * <p>The result is convenient for path comparison. For other uses, * notice that Windows separators ("\") are replaced by simple slashes. * @param path the original path * @return the normalized path */public static String cleanPath(String path) {                //边界处理if (path == null) {return null;}                //用/地体pathToUse的\\String pathToUse = replace(path, WINDOWS_FOLDER_SEPARATOR, FOLDER_SEPARATOR);// Strip prefix from path to analyze, to not treat it as part of the// first path element. This is necessary to correctly parse paths like// "file:core/../core/io/Resource.class", where the ".." should just// strip the first "core" directory while keeping the "file:" prefix.                //找到:的位置int prefixIndex = pathToUse.indexOf(":");String prefix = "";                //如果:不存在if (prefixIndex != -1) {                        //前缀是pathToUse中从0到prefixIndex的字符,包括:prefix = pathToUse.substring(0, prefixIndex + 1);                        //获得冒号之后的所有字符(串)pathToUse = pathToUse.substring(prefixIndex + 1);}if (pathToUse.startsWith(FOLDER_SEPARATOR)) {//如果pathToUse是以/开头                        //把prefix +/prefix = prefix + FOLDER_SEPARATOR;                        //过滤掉开头的/pathToUse = pathToUse.substring(1);}String[] pathArray = delimitedListToStringArray(pathToUse, FOLDER_SEPARATOR);List<String> pathElements = new LinkedList<String>();int tops = 0;for (int i = pathArray.length - 1; i >= 0; i--) {String element = pathArray[i];if (CURRENT_PATH.equals(element)) {// Points to current directory - drop it.}else if (TOP_PATH.equals(element)) {// Registering top path found.tops++;}else {if (tops > 0) {// Merging path element with element corresponding to top path.tops--;}else {// Normal path element found.pathElements.add(0, element);}}}// Remaining top paths need to be retained.for (int i = 0; i < tops; i++) {pathElements.add(0, TOP_PATH);}return prefix + collectionToDelimitedString(pathElements, FOLDER_SEPARATOR);}/** * Compare two paths after normalization of them. * @param path1 first path for comparison * @param path2 second path for comparison * @return whether the two paths are equivalent after normalization */public static boolean pathEquals(String path1, String path2) {return cleanPath(path1).equals(cleanPath(path2));}        //检测是否是有效路径locale的语法是locale -O 64 -a | -m | -c -k Name ... private static void validateLocalePart(String localePart) {for (int i = 0; i < localePart.length(); i++) {char ch = localePart.charAt(i);                       //检测当前字符 if (ch != '_' && ch != ' ' && !Character.isLetterOrDigit(ch)) {throw new IllegalArgumentException("Locale part \"" + localePart + "\" contains invalid characters");}}}//---------------------------------------------------------------------// Convenience methods for working with String arrays//---------------------------------------------------------------------/** * Append the given String to the given String array, returning a new array         *  */public static String[] addStringToArray(String[] array, String str) {                //如果arry==null或者里面没有元素if (ObjectUtils.isEmpty(array)) {return new String[] {str};}                //扩展一个新数组String[] newArr = new String[array.length + 1];                //把array内容复制到newArr里面System.arraycopy(array, 0, newArr, 0, array.length);                //把str添加到数组末尾newArr[array.length] = str;                //返回新数组return newArr;}/**         * 合并两个数组,直接无条件合并,即使两个数组有重复的元素         *  array1空则返回array2 ,array2空则返回array1 */public static String[] concatenateStringArrays(String[] array1, String[] array2) {if (ObjectUtils.isEmpty(array1)) {return array2;}if (ObjectUtils.isEmpty(array2)) {return array1;}                //创建一个新数组String[] newArr = new String[array1.length + array2.length];                //数据复制System.arraycopy(array1, 0, newArr, 0, array1.length);System.arraycopy(array2, 0, newArr, array1.length, array2.length);                //返回一个新数组return newArr;}/**         *合并两个数组,如果两个数组有重复元素的话,只选择一个合并即可 */public static String[] mergeStringArrays(String[] array1, String[] array2) {                //如果array1空的话,返回array2if (ObjectUtils.isEmpty(array1)) {return array2;}                //如果array2空的话,返回array1if (ObjectUtils.isEmpty(array2)) {return array1;}                //定义一个array链表List<String> result = new ArrayList<String>();                //先装array1result.addAll(Arrays.asList(array1));                //把array2跟array1不同的元素装入链表for (String str : array2) {if (!result.contains(str)) {result.add(str);}}                return toStringArray(result);}/** * Turn given source String array into sorted array. * @param array the source array * @return the sorted array (never <code>null</code>) */public static String[] sortStringArray(String[] array) {if (ObjectUtils.isEmpty(array)) {return new String[0];}Arrays.sort(array);return array;}/**         * 把集合转化为数组 */public static String[] toStringArray(Collection<String> collection) {            //边界处理if (collection == null) {return null;}                //toArray(T[] a)把list里面的元素放入a中,并返回areturn collection.toArray(new String[collection.size()]);}/**          *把Enumeration类型转化为数组 */public static String[] toStringArray(Enumeration<String> enumeration) {if (enumeration == null) {return null;}                //先转换为listList<String> list = Collections.list(enumeration);                //toArray(T[] a)把list里面的元素放入a中,并返回areturn list.toArray(new String[list.size()]);}/**         *选择 字符数组array中首部或者尾部都是空白的元素(字符串),去掉其空白 */public static String[] trimArrayElements(String[] array) {                //如果array为空,则返回长度为0的数组if (ObjectUtils.isEmpty(array)) {return new String[0];}                //建立一个length为array.length的数组,其实具体实现上没这个必要String[] result = new String[array.length];for (int i = 0; i < array.length; i++) {                       //获取当前元素String element = array[i];                        //如果当前元素不为空,则返回经过trim处理的字符串                        //trim()此字符串移除了前导和尾部空白的副本,如果没有前导和尾部空白,则返回此字符串。                        //直接array[i] = (element != null ? element.trim() : null);也可以result[i] = (element != null ? element.trim() : null);}                //返回一个新数组return result;}/**         *去掉数组中的重复的元素         * 方法:遍历数组,把元素加入set里自动过滤掉重复的元素,由于使用set,导致处理过的数组         * 是排好序的数组 */public static String[] removeDuplicateStrings(String[] array) {                //如果数组为空,直接返回arrayif (ObjectUtils.isEmpty(array)) {return array;}Set<String> set = new TreeSet<String>();                //循环遍历数组,把数组元素加入到set里for (String element : array) {set.add(element);}                //把set转化为数组return toStringArray(set);}/**          *把一个字符串分按照delimiter分割成两个子字符串,组成数组返回 */public static String[] split(String toSplit, String delimiter) {               //边界处理。个人认为该边界处理的有问题,如果toSplit不为空而delimiter为空的话,返回的最好是原来的字符串组成的              //长度为一的数组 new String[]{toSplit},可该做法直接返回了空值if (!hasLength(toSplit) || !hasLength(delimiter)) {return null;}                //获得delimiter的位置int offset = toSplit.indexOf(delimiter);if (offset < 0) {//此时不符合要求return null;}                //获得在delimiter之前的子字符串String beforeDelimiter = toSplit.substring(0, offset);                //获得在delimiter之后的子字符串String afterDelimiter = toSplit.substring(offset + delimiter.length());                //组成数组返回return new String[] {beforeDelimiter, afterDelimiter};}/** * Take an array Strings and split each element based on the given delimiter. * A <code>Properties</code> instance is then generated, with the left of the * delimiter providing the key, and the right of the delimiter providing the value. * <p>Will trim both the key and value before adding them to the * <code>Properties</code> instance. * @param array the array to process * @param delimiter to split each element using (typically the equals symbol) * @param charsToDelete one or more characters to remove from each element * prior to attempting the split operation (typically the quotation mark * symbol), or <code>null</code> if no removal should occur * @return a <code>Properties</code> instance representing the array contents, * or <code>null</code> if the array to process was <code>null</code> or empty */public static Properties splitArrayElementsIntoProperties(String[] array, String delimiter, String charsToDelete) {if (ObjectUtils.isEmpty(array)) {return null;}Properties result = new Properties();for (String element : array) {if (charsToDelete != null) {element = deleteAny(element, charsToDelete);}String[] splittedElement = split(element, delimiter);if (splittedElement == null) {continue;}result.setProperty(splittedElement[0].trim(), splittedElement[1].trim());}return result;}/** * Tokenize the given String into a String array via a StringTokenizer. * Trims tokens and omits empty tokens. * <p>The given delimiters string is supposed to consist of any number of * delimiter characters. Each of those characters can be used to separate * tokens. A delimiter is always a single character; for multi-character * delimiters, consider using <code>delimitedListToStringArray</code> * @param str the String to tokenize * @param delimiters the delimiter characters, assembled as String * (each of those characters is individually considered as delimiter). * @return an array of the tokens * @see java.util.StringTokenizer * @see java.lang.String#trim() * @see #delimitedListToStringArray */public static String[] tokenizeToStringArray(String str, String delimiters) {return tokenizeToStringArray(str, delimiters, true, true);}/** * Tokenize the given String into a String array via a StringTokenizer. * <p>The given delimiters string is supposed to consist of any number of * delimiter characters. Each of those characters can be used to separate * tokens. A delimiter is always a single character; for multi-character * delimiters, consider using <code>delimitedListToStringArray</code> * @param str the String to tokenize * @param delimiters the delimiter characters, assembled as String * (each of those characters is individually considered as delimiter) * @param trimTokens trim the tokens via String's <code>trim</code> * @param ignoreEmptyTokens omit empty tokens from the result array * (only applies to tokens that are empty after trimming; StringTokenizer * will not consider subsequent delimiters as token in the first place). * @return an array of the tokens (<code>null</code> if the input String * was <code>null</code>) * @see java.util.StringTokenizer * @see java.lang.String#trim() * @see #delimitedListToStringArray */public static String[] tokenizeToStringArray(String str, String delimiters, boolean trimTokens, boolean ignoreEmptyTokens) {if (str == null) {return null;}StringTokenizer st = new StringTokenizer(str, delimiters);List<String> tokens = new ArrayList<String>();while (st.hasMoreTokens()) {String token = st.nextToken();if (trimTokens) {token = token.trim();}if (!ignoreEmptyTokens || token.length() > 0) {tokens.add(token);}}return toStringArray(tokens);}public static String arrayToDelimitedString(Object[] arr, String delim) {               //边界处理if (ObjectUtils.isEmpty(arr)) {return "";}if (arr.length == 1) {                       //把一个对象arr[0]通过调用nullSafeToString转化为Stringreturn ObjectUtils.nullSafeToString(arr[0]);}StringBuilder sb = new StringBuilder();for (int i = 0; i < arr.length; i++) {if (i > 0) {sb.append(delim);}sb.append(arr[i]);}return sb.toString();}}
该类对字符的操作可以直接拿来封装一下,以后方便自己直接用之