001 package ezvcard.util; 002 003 import java.util.ArrayList; 004 import java.util.List; 005 import java.util.regex.Pattern; 006 007 /* 008 Copyright (c) 2012, Michael Angstadt 009 All rights reserved. 010 011 Redistribution and use in source and binary forms, with or without 012 modification, are permitted provided that the following conditions are met: 013 014 1. Redistributions of source code must retain the above copyright notice, this 015 list of conditions and the following disclaimer. 016 2. Redistributions in binary form must reproduce the above copyright notice, 017 this list of conditions and the following disclaimer in the documentation 018 and/or other materials provided with the distribution. 019 020 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 021 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 022 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 023 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 024 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 025 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 026 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 027 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 028 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 029 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 030 031 The views and conclusions contained in the software and documentation are those 032 of the authors and should not be interpreted as representing official policies, 033 either expressed or implied, of the FreeBSD Project. 034 */ 035 036 /** 037 * Helper class for dealing with vCard strings. 038 * @author Michael Angstadt 039 */ 040 public class VCardStringUtils { 041 /** 042 * Unescapes all special characters that are escaped with a backslash, as 043 * well as escaped newlines. 044 * @param text the text 045 * @return the unescaped text 046 */ 047 public static String unescape(String text) { 048 StringBuilder sb = new StringBuilder(text.length()); 049 boolean escaped = false; 050 for (int i = 0; i < text.length(); i++) { 051 char ch = text.charAt(i); 052 if (escaped) { 053 if (ch == 'n' || ch == 'N') { 054 //newlines appear as "\n" or "\N" (see RFC 2426 p.7) 055 sb.append(System.getProperty("line.separator")); 056 } else { 057 sb.append(ch); 058 } 059 escaped = false; 060 } else if (ch == '\\') { 061 escaped = true; 062 } else { 063 sb.append(ch); 064 } 065 } 066 return sb.toString(); 067 } 068 069 /** 070 * Escapes all special characters within a vCard value. 071 * <p> 072 * These characters are: 073 * </p> 074 * <ul> 075 * <li>backslashes (<code>\</code>)</li> 076 * <li>commas (<code>,</code>)</li> 077 * <li>semi-colons (<code>;</code>)</li> 078 * </ul> 079 * @param text the text to escape 080 * @return the escaped text 081 */ 082 public static String escape(String text) { 083 String chars = "\\,;"; 084 for (int i = 0; i < chars.length(); i++) { 085 String ch = chars.substring(i, i + 1); 086 text = text.replace(ch, "\\" + ch); 087 } 088 return text; 089 } 090 091 /** 092 * Escapes all newline characters within a vCard value. 093 * <p> 094 * This method escapes the following newline sequences: 095 * </p> 096 * <ul> 097 * <li><code>\r\n</code></li> 098 * <li><code>\r</code></li> 099 * <li><code>\n</code></li> 100 * </ul> 101 * @param text the text to escape 102 * @return the escaped text 103 */ 104 public static String escapeNewlines(String text) { 105 return text.replaceAll("\\r\\n|\\r|\\n", "\\\\n"); 106 } 107 108 /** 109 * Determines if a string contains one or more newline characters. 110 * @param text the string 111 * @return true if it contains one or more newline characters, false if not 112 */ 113 public static boolean containsNewlines(String text) { 114 return text.contains("\n") || text.contains("\r"); 115 } 116 117 /** 118 * Splits a string by a character, taking escaped characters into account. 119 * Each split value is also trimmed. 120 * <p> 121 * For example: 122 * <p> 123 * <code>splitBy("HE\:LLO::WORLD", ':', false, true)</code> 124 * <p> 125 * returns 126 * <p> 127 * <code>["HE:LLO", "", "WORLD"]</code> 128 * @param str the string to split 129 * @param ch the character to split by 130 * @param removeEmpties true to remove empty elements, false not to 131 * @param unescape true to unescape each split string, false not to 132 * @return the split string 133 * @see <a 134 * href="http://stackoverflow.com/q/820172">http://stackoverflow.com/q/820172</a> 135 */ 136 public static String[] splitBy(String str, char ch, boolean removeEmpties, boolean unescape) { 137 str = str.trim(); 138 String split[] = str.split("\\s*(?<!\\\\)" + Pattern.quote(ch + "") + "\\s*", -1); 139 140 List<String> list = new ArrayList<String>(split.length); 141 for (String s : split) { 142 if (s.length() == 0 && removeEmpties) { 143 continue; 144 } 145 146 if (unescape) { 147 s = unescape(s); 148 } 149 150 list.add(s); 151 } 152 153 return list.toArray(new String[0]); 154 } 155 156 /** 157 * Trims the whitespace off the left side of a string. 158 * @param string the string to trim 159 * @return the trimmed string 160 */ 161 public static String ltrim(String string) { 162 int i; 163 for (i = 0; i < string.length() && Character.isWhitespace(string.charAt(i)); i++) { 164 //do nothing 165 } 166 return (i == string.length()) ? "" : string.substring(i); 167 } 168 169 /** 170 * Trims the whitespace off the right side of a string. 171 * @param string the string to trim 172 * @return the trimmed string 173 */ 174 public static String rtrim(String string) { 175 int i; 176 for (i = string.length() - 1; i >= 0 && Character.isWhitespace(string.charAt(i)); i--) { 177 //do nothing 178 } 179 return (i == 0) ? "" : string.substring(0, i + 1); 180 } 181 182 private VCardStringUtils() { 183 //hide constructor 184 } 185 }