我需要解析一些具有不同类型分隔符的文本文件(波浪号,空格,逗号,管道,插入符号)。
根据分隔符的不同,元素的顺序也不同,例如:
comma: A, B, C, D, E
caret: B, C, A, E, D
tilde: C, A, B, D, E
分隔符在文件中是相同的,但是从一个文件到另一个文件是不同的。据我所知,数据元素中没有分隔符。
在普通的Java中做什么是一个好方法?
答案 0 :(得分:3)
我喜欢阅读文件的前两行,然后测试分隔符。如果你在一个分隔符上拆分,并且两条线都返回相同的非零数量的碎片,那么你可能已经猜到了正确的一个。这是一个检查文件names.txt。
的示例程序public static void main(String[] args) throws IOException {
File file = new File("etc/names.txt");
String delim = getDelimiter(file);
System.out.println("Delim is " + delim + " (" + (int) delim.charAt(0) + ")");
}
private static final String[] DELIMS = new String[] { "\t", ",", " " };
private static String getDelimiter(File file) throws IOException {
for (String delim : DELIMS) {
BufferedReader br = new BufferedReader(new FileReader(file));
String[] line0 = br.readLine().split(delim);
String[] line1 = br.readLine().split(delim);
br.close();
if (line0.length == line1.length && line0.length > 1) {
return delim;
}
}
throw new IllegalStateException("Failed to find delimiter for file " + file);
}
答案 1 :(得分:2)
我可以先玩Java StringTokenizer。这需要一个字符串,并允许您找到由分隔符分隔的每个标记。
Here is one example from the net.
但是你想要从文件中标记出来。在这种情况下,您可能希望使用Java的StreamTokenizer,它允许您解析文件流中的输入。
修改强>
如果您事先不知道分隔符,可以做一些事情:
答案 2 :(得分:1)
如果整个文件中的分隔符相同,则为一个分隔符编写一个函数,将其命名为 d ,并在处理其他文件时,用 d 替换它们的分隔符。冲洗。重复。 :)
另一种方法:让您的解析函数接受文件名和分隔符作为参数。 这假设解析逻辑对于所有文件都是相同的。
如果你的文件看起来完全不同 - 分隔符是你问题最少的。
答案 3 :(得分:1)
如果在整个文件中使用相同的分隔符,那么在加载文件进行解析时可能会输入分隔符。
说出来..
void someFunction(char delimiter){
--- do wateva you want to do with the file --- // you can use stringTokenizer for this purpose
}
每次加载文件时,都可以通过调用文件的分隔符作为参数来使用此函数。
希望这会有所帮助......: - )
答案 4 :(得分:1)
您可以编写一个解析文件的类:
interface MyParser {
public MyParser(char delimiter, List<String> fields);
Map<String,String> ParseFile(InputStream file);
}
您将分隔符和有序的字段列表传递给构造函数,然后要求它解析文件。您将获得一个字段名称(从有序列表)到值的映射。
ParseFile的实现可能会使用split和分隔符,然后迭代遍历split返回的数组和字段列表,并在它开始时创建地图。
答案 5 :(得分:1)
一种可能的方法是使用Java Compiler Compiler(https://javacc.dev.java.net/)。通过这种方式,您可以为您接受的内容和任何时候可能出现的分隔符编写一组规则。根据使用的分隔符,可以为引擎提供处理订单问题的规则。如有必要,该文件可以在此过程中切换分隔符。
答案 6 :(得分:1)
如果在使用特定分隔符时知道记录的确切顺序,我只需创建一个解析器,它将返回每行的Record对象......如下所示。
这确实包含了很多硬编码值,但我不确定你需要多么灵活。我认为这更像是一个脚本/ hacky解决方案,而不是你可以扩展的东西。如果您不知道分隔符,可以使用String.split()方法测试文件的第一行,并查看列数是否与预期计数匹配。
class MyParser
{
public static Record parseLine(String line, char delimiter)
{
StringTokenizer st1 = new StringTokenizer(line, delimiter);
//You could easily use an array instead of these dumb variables
String temp1,temp2,temp3,temp4,temp5;
temp1 = st1.getNextToken();
.. etc..
Record ret = new Record();
switch (delimiter)
{
case '^':
ret.A = temp2;
ret.B = temp3;
...etc...
break;
case '~':
...etc...
break;
}
}
}
class Record
{
String A;
String B;
String C;
String D;
String E:
}
答案 7 :(得分:1)
您可以使用前面提到的StringTokenizer。是的,您需要为所有可能的分隔符指定一个字符串。不要忘记设置tokenizer的“returnsDelims”属性。这样您就可以知道文件中使用了哪个令牌,然后可以相应地解析数据。
答案 8 :(得分:1)
在文件中查找分隔符的一种方法是使用某种正则表达式。一个简单的例子是找到任何非字母或数字的字符:[^ A-Za-z0-9]
static String getDelimiter(String str) {
Pattern p = Pattern.compile("([^A-Za-z0-9])");
Matcher m = p.matcher(str.trim()); //remove whitespace as first char(s)
if(m.find())
return m.group(0);
else
return null;
}
public static void main(String[] args) {
String[] str = {" A, B, C, D", "A B C D", "A;B;C;D"};
for(String s : str){
String[] data = s.split(getDelimiter(s));
//do clever stuff with the array
}
}
在这种情况下,我已经从数组加载数据而不是从文件中读取数据。从文件中读取第一行时,请使用getDelimiter方法。
答案 9 :(得分:0)
大多数开源CSV解析库允许您更改分隔符字符,并且还具有内置的行为来处理转义。 Opencsv现在似乎很受欢迎,但我还没有使用它。上次我不得不进行大量的csv解析时,我对Ostermiller csv library非常满意。