2009-10-28 84 views
25

我正在处理一个制表符分隔的字符串。我正在使用split功能来完成此功能,并且它在大多数情况下都能正常工作。当一个字段丢失时会发生问题,所以不是在该字段中获得空值,而是获得下一个值。我将解析的值存储在一个字符串数组中。在Java中使用分隔符“ t”解析Java字符串

String[] columnDetail = new String[11]; 
columnDetail = column.split("\t"); 

任何帮助,将不胜感激。如果可能的话,我想将解析的字符串存储到一个字符串数组中,以便我可以轻松访问解析的数据。

+0

所以'字段1 \ tfield2 \ t \ tfield4'给你FIELD1,FIELD2,字段4而不是字段1,字段2,[空]字段4? – 2009-10-28 08:08:46

+3

http://stackoverflow.com/questions/1630092/token-parsing-in-java/1630110重复?当你不明白答案并且复制代码时,会发生这种情况。 – 2009-10-28 08:10:21

+2

你不需要分配一个新的字符串数组。无论如何,'String.split'会分配一个新的。 – Joey 2009-10-28 08:10:47

回答

78

String.split使用Regular Expressions,你也不需要为你的分割分配一个额外的数组。

拆分方法会给你一个列表。,问题在于你试图预先定义一个标签有多少次出现,但你怎么知道这一点?尝试使用Scanner或StringTokenizer,并了解分割字符串是如何工作的。

让我解释为什么\ t不起作用以及为什么您需要\\\\转义\\

好的,所以当你使用Split时,它实际上需要一个正则表达式(正则表达式),并且在正则表达式中你要定义要分割的字符,并且如果你写了\ t其实并不意味着\t和什么你想拆分是\t,对吧?所以,只要写\t你告诉你的正则表达式处理器,“嘿拆分字符是逃脱t”不是“嘿拆分所有字符看起来像\t”。注意区别?用\意味着逃避某事。而正则表达式中的\意味着完全不同于你的想法。

所以这就是为什么你需要使用这个解决方案

\\t 

告知regex处理器找\吨。好吧,为什么你需要两个他们?那么,第一个\逃脱第二个,这意味着它会看起来像这样:\ t当你正在处理文本!

现在让我们假设你正在寻找分裂与\

那么,你将留下\\但看,那不行!因为\会试图逃避以前的字符!这就是为什么你希望输出是\\,因此你需要有\\\\。

我真的希望上面的例子可以帮助您理解您的解决方案为什么不起作用以及如何征服其他解决方案!

现在,我已经给你这answer之前,也许你应该现在开始看他们。

其他方法

的StringTokenizer

你应该看看StringTokenizer,这对这类工作的一个非常方便的工具。

StringTokenizer st = new StringTokenizer("this is a test"); 
while (st.hasMoreTokens()) { 
    System.out.println(st.nextToken()); 
} 

这将输出

this 
is 
a 
test 

采用第二种构造的StringTokenizer设置分隔符:

StringTokenizer(String str, String delim)

扫描仪

你也可以使用一个Scanner作为评论员的一个说,这可能看起来有点像这样

String input = "1 fish 2 fish red fish blue fish"; 

Scanner s = new Scanner(input).useDelimiter("\\s*fish\\s*"); 

System.out.println(s.nextInt()); 
System.out.println(s.nextInt()); 
System.out.println(s.next()); 
System.out.println(s.next()); 

s.close(); 

输出将

1 
2 
red 
blue 

这意味着它会切掉“鱼”一词,并给你休息,使用“鱼”作为分隔符。

examples taken from the Java API

+0

@Filip:不错! – 2009-10-28 08:10:43

+2

正则表达式在分页时不应该咬你,但是。 – Joey 2009-10-28 08:11:57

+1

可能不是,但如果OP只是试图阅读答案并理解它们,他已经知道了答案。因为这与他昨天发布的内容相似。我会说,如果他昨天和今天使用我的方法,他不会得到这个问题。 – 2009-10-28 08:13:05

4

String.split的实现将有很大的局限性,如果在制表符分隔场本身的数据包含换行符,标签和可能“字。

制表符分隔的格式已经存在了驴多年,但格式不是标准化的,并且不尽相同许多实现不会转义出现在字段中的字符(换行符和制表符),而是遵循CSV约定并将所有非平凡字段包含在“双引号”中,然后它们只能转义双引号所以一条“线”可以延伸到多条线上。

阅读我听说“只是重用apache工具”,这听起来很好的建议。

最后我个人选择了opencsv。我发现它重量轻,并且由于它提供了用于转义和引用字符的选项,它应该涵盖大多数流行的逗号和制表符分隔的数据格式。

例子:

CSVReader tabFormatReader = new CSVReader(new FileReader("yourfile.tsv"), '\t'); 
15

试试这个:

String[] columnDetail = column.split("\t", -1); 

阅读String.split(java.lang.String, int)的Javadoc有关split函数的极限参数说明:

split 

public String[] split(String regex, int limit) 
Splits this string around matches of the given regular expression. 
The array returned by this method contains each substring of this string that is terminated by another substring that matches the given expression or is terminated by the end of the string. The substrings in the array are in the order in which they occur in this string. If the expression does not match any part of the input then the resulting array has just one element, namely this string. 

The limit parameter controls the number of times the pattern is applied and therefore affects the length of the resulting array. If the limit n is greater than zero then the pattern will be applied at most n - 1 times, the array's length will be no greater than n, and the array's last entry will contain all input beyond the last matched delimiter. If n is non-positive then the pattern will be applied as many times as possible and the array can have any length. If n is zero then the pattern will be applied as many times as possible, the array can have any length, and trailing empty strings will be discarded. 

The string "boo:and:foo", for example, yields the following results with these parameters: 

Regex Limit Result 
: 2 { "boo", "and:foo" } 
: 5 { "boo", "and", "foo" } 
: -2 { "boo", "and", "foo" } 
o 5 { "b", "", ":and:f", "", "" } 
o -2 { "b", "", ":and:f", "", "" } 
o 0 { "b", "", ":and:f" } 

当最后几字段(我的客人,这是你的情况)缺失,你会得到这样的列:

field1\tfield2\tfield3\t\t 

如果没有限制被设定为分割()时,下限为0,这将导致对“后空字符串将被丢弃”。所以你只能得到3个字段,{“field1”,“field2”,“field3”}。

当limit设置为-1时,非正值,尾随空字符串不会被丢弃。所以你可以得到5个字段,最后两个字符串为空字符串,{“field1”,“field2”,“field3”,“”,“”}。

+0

你还应该解释为什么你的解决方案能够工作(例如,'-1'是如何帮助的)。 – brimborium 2012-10-31 13:26:49

+0

现在好吗?但愿如此。感谢您的建议。 – Happy3 2012-11-01 05:18:30

+0

@ Happy3:你给了java1.4文档的链接。我们不应该参考更多最新版本吗? :) – nir 2015-02-18 22:19:47

6

没有人回答 - 这部分是问题的错误:输入字符串包含11个字段(可以推断出这么多),但有多少个标签?最可能正是 10.那么答案是

String s = "\t2\t\t4\t5\t6\t\t8\t\t10\t"; 
String[] fields = s.split("\t", -1); // in your case s.split("\t", 11) might also do 
for (int i = 0; i < fields.length; ++i) { 
    if ("".equals(fields[i])) fields[i] = null; 
} 
System.out.println(Arrays.asList(fields)); 
// [null, 2, null, 4, 5, 6, null, 8, null, 10, null] 
// with s.split("\t") : [null, 2, null, 4, 5, 6, null, 8, null, 10] 

如果字段会包含制表符预期,当然,这是不行的。
-1意味着:根据需要多次应用模式 - 因此尾部字段(第11位)将被保留(如果没有空字符串(""),需要显式地将其转换为null)。

如果在另一方面也有失踪的领域没有标签 - 所以"5\t6"是包含5,6场的有效输入字符串唯一的 - 没有办法通过拆分来获得fields[]

+0

它没有被标记为接受,因为OP在提问后从未返回到网站。 – 2012-12-07 06:47:17

1

我刚刚有同样的问题,并注意到某种教程中的答案。一般来说,你需要使用拆分方法的第二种形式,使用

split(regex, limit)

以下是完整的教程http://www.rgagnon.com/javadetails/java-0438.html

如果你设置一些负数的限制参数,你会得到空字符串在实际值丢失的数组中。要使用它,你的初始字符串应该有两个分隔符的副本,即你应该有\ t \ t值缺失的地方。

希望这有助于:)