解析包含多种分隔符的文本文件的最佳方法?

时间:2009-11-12 04:14:26

标签: java parsing csv delimiter

我需要解析一些具有不同类型分隔符的文本文件(波浪号,空格,逗号,管道,插入符号)。

根据分隔符的不同,元素的顺序也不同,例如:

comma: A, B, C, D, E
caret: B, C, A, E, D
tilde: C, A, B, D, E 

分隔符在文件中是相同的,但是从一个文件到另一个文件是不同的。据我所知,数据元素中没有分隔符。

在普通的Java中做什么是一个好方法?

10 个答案:

答案 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,它允许您解析文件流中的输入。

修改

如果您事先不知道分隔符,可以做一些事情:

  1. 基于所有可能的分隔符划分。如果您的数据本身没有任何分隔符,那么这将起作用。 (即,查找“,”和“;” - 只要您的数据本身没有任何一个字符)
  2. 如果您知道您的数据应该是什么样子(应该是整数,或者应该是单个字符),那么您的代码可以尝试不同的分隔符(首先尝试“,”然后尝试“;”,等)直到它“正确”解析了一行文字。

答案 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非常满意。