Last active
December 21, 2015 17:59
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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