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 }