是否有Java的shlex替代品? 我想能够像shell处理它们一样拆分引号分隔的字符串。例如,如果我发送:
one two "three four"并执行拆分操作,我希望收到标记
one
two
three four
今天我遇到了一个类似的问题,看起来像StringTokenizer、StrTokenizer、Scanner这些标准选项都不太适合。不过,实现基本功能并不难。
这个例子处理了其他答案中目前被评论提及的所有边缘情况。请注意,我尚未检查其是否完全符合POSIX标准。包括单元测试的Gist可以在GitHub上获取——通过unlicense发布到公共领域。
public List<String> shellSplit(CharSequence string) {
List<String> tokens = new ArrayList<String>();
boolean escaping = false;
char quoteChar = ' ';
boolean quoting = false;
int lastCloseQuoteIndex = Integer.MIN_VALUE;
StringBuilder current = new StringBuilder();
for (int i = 0; i<string.length(); i++) {
char c = string.charAt(i);
if (escaping) {
current.append(c);
escaping = false;
} else if (c == '\\' && !(quoting && quoteChar == '\'')) {
escaping = true;
} else if (quoting && c == quoteChar) {
quoting = false;
lastCloseQuoteIndex = i;
} else if (!quoting && (c == '\'' || c == '"')) {
quoting = true;
quoteChar = c;
} else if (!quoting && Character.isWhitespace(c)) {
if (current.length() > 0 || lastCloseQuoteIndex == (i - 1)) {
tokens.add(current.toString());
current = new StringBuilder();
}
} else {
current.append(c);
}
}
if (current.length() > 0 || lastCloseQuoteIndex == (string.length() - 1)) {
tokens.add(current.toString());
}
return tokens;
}
"''"
将被解析为空列表,而不是包含""
的列表。 - j3horg.apache.commons.lang.text.StrTokenizer应该能够做到你想要的:
new StringTokenizer("one two \"three four\"", ' ', '"').getTokenArray();
shlex
不同,commons.lang不兼容POSIX。(-> (StrTokenizer. "\"foo\"'bar'baz") (.getTokenList))
返回一个包含"foo"'bar'baz
的单个条目,而不是(正确的)foobarbaz
。 - Charles Duffy我使用以下Scala代码成功使用fastparse。 我不能保证它完整:
val kvParser = {
import fastparse._
import NoWhitespace._
def nonQuoteChar[_:P] = P(CharPred(_ != '"'))
def quotedQuote[_:P] = P("\\\"")
def quotedElement[_:P] = P(nonQuoteChar | quotedQuote)
def quotedContent[_:P] = P(quotedElement.rep)
def quotedString[_:P] = P("\"" ~/ quotedContent.! ~ "\"")
def alpha[_:P] = P(CharIn("a-zA-Z"))
def digit[_:P] = P(CharIn("0-9"))
def hyphen[_:P] = P("-")
def underscore[_:P] = P("_")
def bareStringChar[_:P] = P(alpha | digit | hyphen | underscore)
def bareString[_:P] = P(bareStringChar.rep.!)
def string[_:P] = P(quotedString | bareString)
def kvPair[_:P] = P(string ~ "=" ~ string)
def commaAndSpace[_:P] = P(CharIn(" \t\n\r").rep ~ "," ~ CharIn(" \t\n\r").rep)
def kvPairList[_:P] = P(kvPair.rep(sep = commaAndSpace))
def fullLang[_:P] = P(kvPairList ~ End)
def res(str: String) = {
parse(str, fullLang(_))
}
res _
}
shlex
做得很好,但许多天真的算法不会。例如,在shell中,“three four”和“three”' 'four是完全等价的,而three\ four
也是如此。 - Charles Duffy