Skip to content

Instantly share code, notes, and snippets.

@dumptruckman
Last active December 21, 2015 17:59
Show Gist options
  • Save dumptruckman/6343908 to your computer and use it in GitHub Desktop.
Save dumptruckman/6343908 to your computer and use it in GitHub Desktop.
A utility class that will take an array of string arguments and return an array where any arguments surrounded in quotes (single or double) are joined into single strings.
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* A utility which will join together arguments based on the use of quotations.
*/
public class ArgumentJoiner {
/**
* Takes an array of strings which represent command line arguments (space separated) and parses them in order
* to join together multiple arguments enclosed in quotes as single strings in a new array.
* <p/>
* Example:
* - Input = { a | 'b | c | d' | "e | f | g" | h"i | j" | "k | l'm | n" | 'o | p | q }
* - Output = { a | b c d | e f g | h"i | j" | k l'm n | 'o | p | q }
*/
public static String[] joinArgsWithQuotes(String[] args) {
return new ArgumentJoiner(args).joinArgsWithQuotes();
}
/**
* A self test of sorts. Ignore this method unless you're just wanting to make sure this class is working properly.
*/
public static void main(String[] args) {
String[] argsThatShouldTestAllCases = new String[] {
"a","'b","c","d'","\"e","f","g\"","h\"i","j\"","\"k","l'm","n\"","'o","p","q"
};
List<String> expectedResult = Arrays.asList(
"a","b c d","e f g","h\"i","j\"","k l'm n","'o","p","q"
);
List<String> actualResult = Arrays.asList(joinArgsWithQuotes(argsThatShouldTestAllCases));
if (!actualResult.equals(expectedResult)) {
System.out.println("Expected: " + expectedResult);
System.out.println(" Actual: " + actualResult);
throw new AssertionError("Shit don't work");
}
}
private static enum QuoteState {
NO_QUOTES, SINGLE_QUOTES, DOUBLE_QUOTES
}
private String[] initialArgs;
private List<String> parsedArgs;
private QuoteState quoteState;
private StringBuilder quotedArgsBuffer;
private List<String> fallBackBuffer;
ArgumentJoiner(String[] args) {
this.initialArgs = args;
}
private String[] joinArgsWithQuotes() {
quoteState = QuoteState.NO_QUOTES;
parsedArgs = new ArrayList<String>(initialArgs.length);
quotedArgsBuffer = new StringBuilder();
fallBackBuffer = new ArrayList<String>(initialArgs.length);
for (String arg : initialArgs) {
parseSingleArg(arg);
}
dealWithAnyUnclosedQuotes();
return parsedArgs.toArray(new String[parsedArgs.size()]);
}
private void parseSingleArg(String arg) {
if (arg.isEmpty())
return;
fallBackBuffer.add(arg);
switch (quoteState) {
case NO_QUOTES:
parseUnquotedArg(arg);
break;
default:
quotedArgsBuffer.append(' ');
parseQuotedArg(arg);
break;
}
}
private void parseUnquotedArg(String arg) {
char firstChar = arg.charAt(0);
if (firstChar == '\'') {
quoteState = QuoteState.SINGLE_QUOTES;
arg = removeInitialQuote(arg);
parseQuotedArg(arg);
} else if (firstChar == '\"') {
quoteState = QuoteState.DOUBLE_QUOTES;
arg = removeInitialQuote(arg);
parseQuotedArg(arg);
} else {
parsedArgs.add(arg);
}
}
private String removeInitialQuote(String arg) {
if (arg.length() > 1) {
return arg.substring(1);
}
return "";
}
private void parseQuotedArg(String arg) {
if (arg.isEmpty()) {
return;
}
char lastChar = arg.charAt(arg.length() - 1);
if (charIsQuoteMatchingState(lastChar) && endQuoteIsNotEscaped(arg)) {
arg = removeFinalQuote(arg);
quotedArgsBuffer.append(arg);
parsedArgs.add(quotedArgsBuffer.toString());
resetQuotedArgTracking();
} else {
quotedArgsBuffer.append(arg);
}
}
private boolean charIsQuoteMatchingState(char c) {
return (c == '\'' && quoteState == QuoteState.SINGLE_QUOTES) || (c == '\"' && quoteState == QuoteState.DOUBLE_QUOTES);
}
private boolean endQuoteIsNotEscaped(String arg) {
return arg.length() <= 1 || arg.charAt(arg.length() - 2) != '\\';
}
private String removeFinalQuote(String arg) {
if (arg.length() > 1) {
return arg.substring(0, arg.length() - 1);
}
return "";
}
private void resetQuotedArgTracking() {
quotedArgsBuffer.delete(0, quotedArgsBuffer.length());
fallBackBuffer.clear();
quoteState = QuoteState.NO_QUOTES;
}
private void dealWithAnyUnclosedQuotes() {
if (quoteState != QuoteState.NO_QUOTES && !fallBackBuffer.isEmpty()) {
parsedArgs.addAll(fallBackBuffer);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment