001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.camel.util; 018 019import java.util.ArrayList; 020import java.util.List; 021 022/** 023 * Utility class for parsing quoted string which is intended for parameters, separated by comma. 024 */ 025public final class StringQuoteHelper { 026 027 private StringQuoteHelper() { 028 } 029 030 /** 031 * Returns the text wrapped double quotes 032 */ 033 public static String doubleQuote(String text) { 034 return quote(text, "\""); 035 } 036 037 /** 038 * Returns the text wrapped single quotes 039 */ 040 public static String singleQuote(String text) { 041 return quote(text, "'"); 042 } 043 044 /** 045 * Wraps the text in the given quote text 046 * 047 * @param text the text to wrap in quotes 048 * @param quote the quote text added to the prefix and postfix of the text 049 * 050 * @return the text wrapped in the given quotes 051 */ 052 public static String quote(String text, String quote) { 053 return quote + text + quote; 054 } 055 056 /** 057 * Splits the input safely honoring if values is enclosed in quotes. 058 * <p/> 059 * Though this method does not support double quoting values. A quoted value must start with the same start and 060 * ending quote, which is either a single quote or double quote value. 061 * <p/> 062 * Will <i>trim</i> each split value by default. 063 * 064 * @param input the input 065 * @param separator the separator char to split the input, for example a comma. 066 * @return the input split, or <tt>null</tt> if the input is null. 067 */ 068 public static String[] splitSafeQuote(String input, char separator) { 069 return splitSafeQuote(input, separator, true, false); 070 } 071 072 /** 073 * Splits the input safely honoring if values is enclosed in quotes. 074 * <p/> 075 * Though this method does not support double quoting values. A quoted value must start with the same start and 076 * ending quote, which is either a single quote or double quote value. 077 * 078 * @param input the input 079 * @param separator the separator char to split the input, for example a comma. 080 * @param trim whether to trim each split value 081 * @return the input split, or <tt>null</tt> if the input is null. 082 */ 083 public static String[] splitSafeQuote(String input, char separator, boolean trim) { 084 return splitSafeQuote(input, separator, trim, false); 085 } 086 087 /** 088 * Splits the input safely honoring if values is enclosed in quotes. 089 * <p/> 090 * Though this method does not support double quoting values. A quoted value must start with the same start and 091 * ending quote, which is either a single quote or double quote value. 092 * 093 * @param input the input 094 * @param separator the separator char to split the input, for example a comma. 095 * @param trim whether to trim each split value 096 * @param keepQuotes whether to keep quotes 097 * @return the input split, or <tt>null</tt> if the input is null. 098 */ 099 public static String[] splitSafeQuote(String input, char separator, boolean trim, boolean keepQuotes) { 100 if (input == null) { 101 return null; 102 } 103 104 if (input.indexOf(separator) == -1) { 105 if (input.length() > 1) { 106 char ch = input.charAt(0); 107 char ch2 = input.charAt(input.length() - 1); 108 boolean singleQuoted = ch == '\'' && ch2 == '\''; 109 boolean doubleQuoted = ch == '"' && ch2 == '"'; 110 if (!keepQuotes && (singleQuoted || doubleQuoted)) { 111 input = input.substring(1, input.length() - 1); 112 // do not trim quoted text 113 } else if (trim) { 114 input = input.trim(); 115 } 116 } 117 // no separator in data, so return single string with input as is 118 return new String[] { input }; 119 } 120 121 List<String> answer = new ArrayList<>(); 122 StringBuilder sb = new StringBuilder(); 123 124 boolean singleQuoted = false; 125 boolean doubleQuoted = false; 126 boolean separating = false; 127 128 for (int i = 0; i < input.length(); i++) { 129 char ch = input.charAt(i); 130 char prev = i > 0 ? input.charAt(i - 1) : 0; 131 boolean isQuoting = singleQuoted || doubleQuoted; 132 boolean last = i == input.length() - 1; 133 134 if (!doubleQuoted && ch == '\'') { 135 if (singleQuoted && prev == ch && sb.isEmpty()) { 136 // its an empty quote so add empty text 137 if (keepQuotes) { 138 answer.add("''"); 139 } else { 140 answer.add(""); 141 } 142 } 143 // special logic needed if this quote is the end 144 if (last) { 145 if (singleQuoted && !sb.isEmpty()) { 146 String text = sb.toString(); 147 // do not trim a quoted string 148 if (keepQuotes) { 149 answer.add(text + "'"); // append ending quote 150 } else { 151 answer.add(text); 152 } 153 sb.setLength(0); 154 } 155 break; // break out as we are finished 156 } 157 singleQuoted = !singleQuoted; 158 if (keepQuotes) { 159 sb.append(ch); 160 } 161 continue; 162 } else if (!singleQuoted && ch == '"') { 163 if (doubleQuoted && prev == ch && sb.isEmpty()) { 164 // its an empty quote so add empty text 165 if (keepQuotes) { 166 answer.add("\""); // append ending quote 167 } else { 168 answer.add(""); 169 } 170 } 171 // special logic needed if this quote is the end 172 if (last) { 173 if (doubleQuoted && !sb.isEmpty()) { 174 String text = sb.toString(); 175 // do not trim a quoted string 176 if (keepQuotes) { 177 answer.add(text + "\""); 178 } else { 179 answer.add(text); 180 } 181 sb.setLength(0); 182 } 183 break; // break out as we are finished 184 } 185 doubleQuoted = !doubleQuoted; 186 if (keepQuotes) { 187 sb.append(ch); 188 } 189 continue; 190 } else if (!isQuoting && ch == separator) { 191 separating = true; 192 // add as answer if we are not in a quote 193 if (!sb.isEmpty()) { 194 String text = sb.toString(); 195 if (trim) { 196 text = text.trim(); 197 } 198 answer.add(text); 199 sb.setLength(0); 200 } 201 // we should avoid adding the separator 202 continue; 203 } 204 205 if (trim && !isQuoting && separating && separator != ' ' && ch == ' ') { 206 continue; 207 } 208 separating = false; 209 210 // append char 211 sb.append(ch); 212 } 213 214 // any leftover 215 if (!sb.isEmpty()) { 216 String text = sb.toString(); 217 if (trim) { 218 text = text.trim(); 219 } 220 answer.add(text); 221 } 222 223 return answer.toArray(new String[0]); 224 } 225 226}