001/* 002 * Syncany, www.syncany.org 003 * Copyright (C) 2011-2016 Philipp C. Heckel <philipp.heckel@gmail.com> 004 * 005 * This program is free software: you can redistribute it and/or modify 006 * it under the terms of the GNU General Public License as published by 007 * the Free Software Foundation, either version 3 of the License, or 008 * (at your option) any later version. 009 * 010 * This program is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 013 * GNU General Public License for more details. 014 * 015 * You should have received a copy of the GNU General Public License 016 * along with this program. If not, see <http://www.gnu.org/licenses/>. 017 */ 018package org.syncany.util; 019 020import java.io.PrintWriter; 021import java.io.StringWriter; 022import java.io.UnsupportedEncodingException; 023import java.util.Arrays; 024import java.util.List; 025 026/** 027 * Utility class for common application string functions. 028 * 029 * @author Philipp C. Heckel (philipp.heckel@gmail.com) 030 */ 031public class StringUtil { 032 /** 033 * Transforms a string to a camel case representation, including the 034 * first character. 035 * 036 * <p>Examples: 037 * <ul> 038 * <li><code>toCamelCase("hello world") -> "HelloWorld"</code></li> 039 * <li><code>toCamelCase("hello_world") -> "HelloWorld"</code></li> 040 * <li><code>toCamelCase("hello_World") -> "HelloWorld"</code></li> 041 * <li><code>toCamelCase("helloWorld") -> "HelloWorld"</code></li> 042 * <li><code>toCamelCase("HelloWorld") -> "HelloWorld"</code></li> 043 * </ul> 044 */ 045 public static String toCamelCase(String str) { 046 StringBuilder sb = new StringBuilder(); 047 048 for (String s : str.split("[-_ ]")) { 049 if (s.length() > 0) { 050 sb.append(Character.toUpperCase(s.charAt(0))); 051 052 if (s.length() > 1) { 053 sb.append(s.substring(1, s.length())); 054 } 055 } 056 } 057 058 return sb.toString(); 059 } 060 061 /** 062 * Transforms a string to underscore-delimited representation. 063 * 064 * <p>Examples: 065 * <ul> 066 * <li><code>toUnderScoreDelimited("HelloWorld") -> "hello_world"</code></li> 067 * <li><code>toUnderScoreDelimited("helloWorld") -> "hello_world"</code></li> 068 * </ul> 069 */ 070 public static String toSnakeCase(String str) { 071 StringBuilder sb = new StringBuilder(); 072 073 for (char c : str.toCharArray()) { 074 if (Character.isLetter(c) || Character.isDigit(c)) { 075 if (Character.isUpperCase(c)) { 076 if (sb.length() > 0) { 077 sb.append("_"); 078 } 079 080 sb.append(Character.toLowerCase(c)); 081 } else { 082 sb.append(c); 083 } 084 } else { 085 sb.append("_"); 086 } 087 } 088 089 return sb.toString(); 090 } 091 092 /** 093 * Converts a byte array to a lower case hex representation. 094 * If the given byte array is <code>null</code>, an empty string is returned. 095 */ 096 public static String toHex(byte[] bytes) { 097 if (bytes == null) { 098 return ""; 099 } else { 100 final char[] hexArray = "0123456789ABCDEF".toCharArray(); 101 char[] hexChars = new char[bytes.length * 2]; 102 for (int j = 0; j < bytes.length; j++) { 103 int v = bytes[j] & 0xFF; 104 hexChars[j * 2] = hexArray[v >>> 4]; 105 hexChars[j * 2 + 1] = hexArray[v & 0x0F]; 106 } 107 return String.valueOf(hexChars).toLowerCase(); 108 } 109 } 110 111 /** 112 * Creates byte array from a hex represented string. 113 */ 114 public static byte[] fromHex(String hexString) { 115 if (hexString.length() % 2 == 1) { 116 throw new IllegalArgumentException("hex string must be of even length"); 117 } 118 119 char[] hex = hexString.toCharArray(); 120 byte[] raw = new byte[hex.length / 2]; 121 for (int src = 0, dst = 0; dst < raw.length; ++dst) { 122 int hi = Character.digit(hex[src++], 16); 123 int lo = Character.digit(hex[src++], 16); 124 if ((hi < 0) || (lo < 0)) 125 throw new IllegalArgumentException(); 126 raw[dst] = (byte) (hi << 4 | lo); 127 } 128 return raw; 129 } 130 131 /** 132 * Creates a byte array from a given string, using the UTF-8 133 * encoding. This calls {@link String#getBytes(java.nio.charset.Charset)} 134 * internally with "UTF-8" as charset. 135 */ 136 public static byte[] toBytesUTF8(String s) { 137 try { 138 return s.getBytes("UTF-8"); 139 } catch (UnsupportedEncodingException e) { 140 throw new RuntimeException("JVM does not support UTF-8 encoding.", e); 141 } 142 } 143 144 /** 145 * Returns the count of the substring 146 */ 147 public static int substrCount(String haystack, String needle) { 148 int lastIndex = 0; 149 int count = 0; 150 151 if (needle != null && haystack != null) { 152 while (lastIndex != -1) { 153 lastIndex = haystack.indexOf(needle, lastIndex); 154 155 if (lastIndex != -1) { 156 count++; 157 lastIndex += needle.length(); 158 } 159 } 160 } 161 162 return count; 163 } 164 165 public static String getStackTrace(Exception exception) { 166 StringWriter stackTraceStringWriter = new StringWriter(); 167 exception.printStackTrace(new PrintWriter(stackTraceStringWriter)); 168 169 return stackTraceStringWriter.toString(); 170 } 171 172 public static <T> String join(List<T> objects, String delimiter, StringJoinListener<T> listener) { 173 StringBuilder objectsStr = new StringBuilder(); 174 175 for (int i = 0; i < objects.size(); i++) { 176 if (listener != null) { 177 objectsStr.append(listener.getString(objects.get(i))); 178 } else { 179 objectsStr.append(objects.get(i).toString()); 180 } 181 182 if (i < objects.size() - 1) { 183 objectsStr.append(delimiter); 184 } 185 } 186 187 return objectsStr.toString(); 188 } 189 190 public static <T> String join(List<T> objects, String delimiter) { 191 return join(objects, delimiter, null); 192 } 193 194 public static <T> String join(T[] objects, String delimiter, StringJoinListener<T> listener) { 195 return join(Arrays.asList(objects), delimiter, listener); 196 } 197 198 public static <T> String join(T[] objects, String delimiter) { 199 return join(Arrays.asList(objects), delimiter, null); 200 } 201 202 public static interface StringJoinListener<T> { 203 public String getString(T object); 204 } 205}