001/* Copyright (C) 2013 TU Dortmund
002 * This file is part of AutomataLib, http://www.automatalib.net/.
003 * 
004 * AutomataLib is free software; you can redistribute it and/or
005 * modify it under the terms of the GNU Lesser General Public
006 * License version 3.0 as published by the Free Software Foundation.
007 * 
008 * AutomataLib is distributed in the hope that it will be useful,
009 * but WITHOUT ANY WARRANTY; without even the implied warranty of
010 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
011 * Lesser General Public License for more details.
012 * 
013 * You should have received a copy of the GNU Lesser General Public
014 * License along with AutomataLib; if not, see
015 * http://www.gnu.de/documents/lgpl.en.html.
016 */
017package net.automatalib.commons.util.strings;
018
019import java.io.IOException;
020import java.util.regex.Pattern;
021
022/**
023 * Misceallanous utility functions for {@link String}s.
024 * 
025 * @author Malte Isberner <malte.isberner@gmail.com>
026 */
027public abstract class StringUtil {
028        
029        private static final String IDENTIFIER_REGEX = "[a-zA-Z_]\\w*";
030        
031        private static Pattern identifierPattern = null;
032        
033        private StringUtil() {}
034        
035
036        public static Pattern getIdentifierPattern() {
037                if(identifierPattern == null)
038                        identifierPattern = Pattern.compile(IDENTIFIER_REGEX);
039                return identifierPattern;
040        }
041        
042        public static String enquote(String s) {
043                StringBuilder sb = new StringBuilder(s.length() + 2);
044                try {
045                        enquote(s, sb);
046                }
047                catch(IOException e) {}
048                return sb.toString();
049        }
050        
051        public static void enquote(String s, Appendable a) throws IOException {
052                a.append('"');
053                escapeQuotes(s, a);
054                a.append('"');
055        }
056        
057        public static void enquoteIfNecessary(String s, Appendable a) throws IOException {
058                if(!getIdentifierPattern().matcher(s).matches())
059                        enquote(s, a);
060                else
061                        a.append(s);
062        }
063        
064        public static void enquoteIfNecessary(String s, Appendable a, Pattern valid)
065                        throws IOException {
066                if(!valid.matcher(s).matches())
067                        enquote(s, a);
068                else
069                        a.append(s);
070        }
071        
072        public static void enquoteIfNecessary(String s, Appendable a,
073                        Pattern valid,
074                        Pattern exception) throws IOException {
075                if(!valid.matcher(s).matches() || exception.matcher(s).matches())
076                        enquote(s, a);
077                else
078                        a.append(s);
079        }
080        
081        public static String unquote(String s) {
082                StringBuilder sb = new StringBuilder(s.length() - 2);
083                try {
084                        unquote(s, sb);
085                }
086                catch(IOException e) {}
087                return sb.toString();
088        }
089        
090        public static void unquote(String s, Appendable a) throws IOException {
091                if(s.charAt(0) != '"' || s.charAt(s.length()-1) != '"')
092                        throw new IllegalArgumentException("Argument to StringUtil.unquote() must begin and end with a double quote ('\"').");
093                unescapeQuotes(s.substring(1, s.length()-1));
094        }
095        
096        /**
097         * Unescapes escaped double quotes in a string, i.e.
098         * replaces <code>\"</code> by <code>"</code> and
099         * <code>\\</code> by <code>\</code>.
100         * 
101         * @param s the string in which to unescape double quotes.
102         * @return the unescaped string.
103         */
104        public static String unescapeQuotes(String s) {
105                StringBuilder sb = new StringBuilder(s.length());
106                try {
107                        unescapeQuotes(s, sb);
108                }
109                catch(IOException e) {}
110                return sb.toString();
111        }
112        
113        public static void unescapeQuotes(String s, Appendable a) throws IOException {
114                int eos = s.length() - 1;
115                for(int i = 0; i < eos; i++) {
116                        char c = s.charAt(i);
117                        if(c == '\\') {
118                                c = s.charAt(++i);
119                                if(c != '"' && c != '\\')
120                                        a.append('\\');
121                        }
122                        a.append(c);
123                }
124                
125                a.append(s.charAt(eos));
126        }
127
128        /**
129         * Escapes double quotes in a string. Effectively, <code>"</code> is
130         * replaced by <code>\"</code> and <code>\</code> is replaced by
131         * <code>\\</code>.
132         * 
133         * @param s the string to escape.
134         * @return the escaped string.
135         */
136        public static String escapeQuotes(String s) {
137                StringBuilder sb = new StringBuilder(s.length());
138                try {
139                        escapeQuotes(s, sb);
140                }
141                catch(IOException e) {}
142                return sb.toString();
143        }
144        
145        public static void escapeQuotes(String s, Appendable a) throws IOException {
146                for(int i = 0; i < s.length(); i++) {
147                        char c = s.charAt(i);
148                        
149                        if(c == '\\' || c == '"')
150                                a.append('\\');
151                        a.append(c);
152                }
153        }
154        
155        
156        public static void appendObject(Appendable a, Object obj) throws IOException {
157                if(obj instanceof Printable)
158                        ((Printable)obj).print(a);
159                else
160                        a.append(String.valueOf(obj));
161        }
162        
163        public static void appendArray(Appendable a, Object[] array, String sepString) throws IOException {
164                boolean first = true;
165                
166                for(Object o : array) {
167                        if(first)
168                                first = false;
169                        else
170                                a.append(sepString);
171                        appendObject(a, o);
172                }
173        }
174        
175        public static void appendArrayEnquoted(Appendable a, Object[] array, String sepString) throws IOException {
176                boolean first = true;
177                
178                for(Object o : array) {
179                        if(first)
180                                first = false;
181                        else
182                                a.append(sepString);
183                        enquote(String.valueOf(o), a);
184                }
185        }
186        
187        public static void appendIterable(Appendable a, Iterable<?> it, String sepString) throws IOException {
188                boolean first = true;
189                
190                for(Object o : it) {
191                        if(first)
192                                first = false;
193                        else
194                                a.append(sepString);
195                        appendObject(a, o);
196                }
197        }
198        
199        public static void appendIterableEnquoted(Appendable a, Iterable<?> it, String sepString) throws IOException {
200                boolean first = true;
201                
202                for(Object o : it) {
203                        if(first)
204                                first = false;
205                        else
206                                a.append(sepString);
207                        if(o == null)
208                                a.append("null");
209                        else
210                                enquote(o.toString(), a);
211                }
212        }
213}