在Java中,解析字符串的有效方法是什么?

6
我应该如何使用Java解析以下字符串以提取文件路径? 代表任意数量的随机字符 _代表任意数量的空格(无换行符)
?[LoadFile]_file_=_"foo/bar/baz.xml"?

例子:

10:52:21.212 [LoadFile] file = "foo/bar/baz.xml"

需要提取 foo/bar/baz.xml

5个回答

12
String regex = ".*\\[LoadFile\\]\\s+file\\s+=\\s+\"([^\"].+)\".*";

Matcher m = Pattern.compile(regex).matcher(inputString);
if (!m.find()) 
    System.out.println("No match found.");
else
    String result = m.group(1);

结果中的String应该是您的文件路径。(假设我没有犯任何错误

您应该查看Pattern类,以获取一些正则表达式帮助。它们可以成为非常强大的字符串操作工具。


".\[LoadFile\]\sfile\s*=\s* "([^\"].)"." 更好的匹配任意数量的空格。 - Jean
1
"."([^\"].)".*" 更好,因为我们根本不关心前缀格式(默认已知),它也不包含任何引号。 - gizmo
Jean的正则表达式也会匹配无空格的情况,例如[LoadFile]file="foo/bar/baz.xml"。因此,如果您想要至少一个空格字符,请使用jinguy最初指定的+而不是*。 - Peter Di Cecco
@weenaak:我会把“任意数量的空格”理解为包括零在内的任意数量。 - Stephen C
两个更正:创建Matcher对象的方法是.matcher(inputString)(不要大写),您必须调用Matcher上的.matches().find()应用正则表达式。 - Alan Moore

3

简短回答:使用 subSequence() 方法。

if (line.contains("[LoadFile]"))
  result = line.subSequence(line.indexOf('"'), line.lastIndexOf('"')).toString();

在我的机器上,这通常只需要少于10,000纳秒。 我理解“高效”表示更快。 “regex”选项要慢得多(大约慢9到10倍)。使用“regex”选项的主要优点是它可能更容易为其他程序员弄清楚您正在做什么(但是,请使用注释来帮助他们)。 为了使“regex”选项更加高效,先预编译它:
private static final String FILE_REGEX = ".*\\[LoadFile\\]\\s+file\\s+=\\s+\"([^\"].+)\".*";
private static final Pattern FILE_PATTERN = Pattern.compile(FILE_REGEX);

但这仍然使它变慢了。我记录的时间在80,000到100,000纳秒之间。

StringTokenizer选项比正则表达式更有效:

if (line.contains("[LoadFile]")) {
  StringTokenizer tokenizer = new StringTokenizer(line, "\"");
  tokenizer.nextToken();
  result = tokenizer.nextToken();
}

这对我来说大约是40,000 ns,比正则表达式快2-3倍。

在这种情况下,split()也是一种选择,对我来说(使用Java 6_13),它比Tokenizer稍快一点:

if (line.contains("[LoadFile]")) {
  String[] values = line.split("\"");
  result = values[1];
}

这对我来说的平均时间是35,000纳秒。

当然,这些都没有检查错误。当你开始考虑这一点时,每个选项都会变得稍微慢一些,但我认为subSequnce()选项仍然能够击败它们所有。您必须知道确切的参数和期望,以确定每个选项需要多容错。


2

虽然正则表达式很好用,但你也可以使用类java.util.StringTokenizer来完成任务。优点是代码更加人性化。

StringTokenizer tokenizer = new StringTokenizer(inputString, "\"");
tokenizer.nextElement();
String path = tokenizer.nextElement();

好的,我会尽力而为。


StringTokenizer的另一个优点是,它可能更有效率...前提是它能够胜任手头的工作。 - Stephen C
只是如果第一组随机字符中恰好有许多“字符”,分词器将愉快地将其作为下一个元素返回。然而,示例表明输入行的第一部分只是一个时间戳。正则表达式更难编写,但能够处理非常不同的输入。 - Jeroen van Bergen
我同意StringTokenizer并不是每个解析问题的理想解决方案,但在这种情况下,使用正则表达式就像用加农炮打苍蝇一样有些大材小用了... - Yuval

1

4
有些人在回答 Stack Overflow 的问题时,会说“java.util.regex是你的朋友”。现在提问者有了两个问题。(自 http://blogs.msdn.com/oldnewthing/archive/2006/03/22/558007.aspx 自由改编)-- 如果你要建议使用正则表达式,请提供一个例子。 - Grant Wagner
1
@Grant Wagner我认为将人们指向正确的方向没有什么问题,即使我没有时间解决完整的问题。如果你不满意这个答案,那就给出一个更好的答案,而不是浪费时间抱怨。 - starblue

1

你可以将正则表达式缩短一点,比jinguy的更简洁。基本上只需要右侧的部分而不需要引号。

    String regex = ".* = \"(.*)\"";

我认为jinguy假设只有当行中包含[LoadFile]时,路径才应该被提取... - Jean
当我编写正则表达式时,我尽可能地尝试提供具体明确的匹配规则。 - jjnguy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接