我怎样才能最好地解析这个以逗号分隔的文本文件?

时间:2009-01-15 23:05:51

标签: parsing csv delimited-text

我试图找出解析这个以逗号分隔的文本文件的最佳方法。这是一段摘录:

bldgA, fred, lunch
bldgA, sally, supper
bldgB, bob, parking lot
bldgB, frank, rooftop
...

我要做的是读“bldgA”然后我想要那个人(第2栏),“fred”例如。但是我不想解析文件寻找“fred”因为fred可能不会在那里,而bldgA总是会在那里。我想阅读文本文件,看到我在bldgA上,并阅读我的列表中的下一个项目,即fred。之后,我想测试它是否是fred,sally等,并打印出第三列。我知道使用数据库可能会更容易,但对于一个小文本文件似乎有点开销,所以我可以命名列。在我使用Access或其他小东西之前,我想我会尝试Stack Overflow。这就是我所拥有的:

string BuildingFile = Server.MapPath("buildings.txt");
StreamReader FileStreamReader;

FileStreamReader = File.OpenText(BuildingFile);

while (FileStreamReader.Peek() != -1)
{   
    string[] words;
    words = FileStreamReader.ReadLine().Split(',');

    foreach (string word in words)
    {
        if (word == "bldgA")
        {
            //but since word is only on "bldgA" 
            //how can I get the next item in the list which 
            //is on the same line?

            //print out the name of the person and then the duty
        }
        if (word == "bldgB")
        {
            //same as A   
        }
    }

}
FileStreamReader.Close();

我的最终输出是

“你在bldgA,你的名字是弗雷德,你的职责是午餐”

8 个答案:

答案 0 :(得分:3)

如果你知道文件的格式是否正确,你可以做一些事情(使用你的代码,假设语言是C#):

String MyLocation = System.Net.Dns.GetHostName();

string MachineFile = Server.MapPath("buildings.txt");
StreamReader FileStreamReader;

FileStreamReader = File.OpenText(MachineFile);

while (FileStreamReader.Peek() != -1)
{   
    string[] words;
    words = FileStreamReader.ReadLine().Split(',');

    if(words.Length == 3)
    {
        StringBuilder output = new StringBUilder;
        output.Append("You are in ");
        output.Append(words[0]);
        output.Append(" and your name is ");
        output.Append(words[1]);
        output.Append(" and your duty is ");
        output.AppendLine(words[2]);
    }
}
FileStreamReader.Close();

答案 1 :(得分:2)

使用FileHelpers库。它允许您创建用于存储数据的类,并提供一种简单的方法来解析数据存储(包括csv)以填充这些类。

但是,正如您所建议的那样,这似乎是数据库的工作。我考虑SQLite

答案 2 :(得分:1)

为什么不做这样的事情,而不是使用foreach循环:

words = FileStreamReader.ReadLine().Split(',', 3);
StringBuilder output = new StringBuilder();
if (words.Length >= 1)
{
    output.AppendFormat("You are in {0}", words[0]);
    if (words.Length >= 2)
    {
        output.AppendFormat(" and your name is {0}", words[1]);
        if (words.Length >= 3)
        {
            output.AppendFormat(" and your duty is {0}", words[2]);
        }
    }
}
Console.WriteLine(output.ToString()); // or write wherever else you want your output to go

答案 3 :(得分:1)

对象数据库更适合您的解决方案。您可以使用db4o,非常好的开源源代码。

但如果您坚持使用逗号分隔文件,请查看此CsvReader,您可以使用它来读取文件。

答案 4 :(得分:0)

基本上使用状态机。有一个名为“building”的变量,并在遇到建筑物名称时将其存储在那里。然后是人们在该建筑物上运行的人名的案例。

你的解释不是很清楚,你的例子很奇怪。如果你可以改写,我很可能会提供更好的答案。

答案 5 :(得分:0)

我认为你的摘录是这样的:

  

bldgA,弗雷,午餐
  bldgA,莎莉,夜宵
  bldgB,bob,停车场
  bldgB,frank,roof

获得所需输出的步骤:

  • 读一行
  • 沿着逗号分割线
  • 使用拆分功能
  • 返回的部件格式化您想要的输出

split函数通常是正则表达式库的一部分。

在Common Lisp中,这可以这样写:

(defun show-people-status (filename)
  (with-open-file (input-stream filename)
    (do ((line (read-line input-stream nil nil)
               (read-line input-stream nil nil)))
        ((null line) t)
      (apply #'format t "You are in ~a, your name is ~a, and your duty is ~a.~%"
             (cl-ppcre:split "," line)))))

在Perl中,您可以使用以下内容:

#!/usr/bin/perl -w
use strict;

use Tie::File;

tie (@data, 'Tie::File', $ARGV[0]);

foreach (@data) {
    (my $Building, my $Name, my $Duty) = split (/,/);
    print "You are in $Building, your name is $Name, and your duty is $Duty."; };

请注意,Perl版本旨在作为独立脚本,而CL版本显示要从运行时使用的函数。两者都没有输入检查。

答案 6 :(得分:0)

在伪代码中:

#!/usr/bin/env python
import csv

with open('buildings.txt') as csvfile:
    for building, name, duty in csv.reader(csvfile):
        print("You are in %(building)s"
              " and your name is %(name)s"
              " and your duty is %(duty)s" % vars()) 

答案 7 :(得分:0)

原谅我用这种方式编程,但我认为它可以解决你的问题。

我做的唯一假设是在buildings.txt中的某个地方有一个名为“bldgA”的列,右边总共有2列,这些是你想要的数据。

private static int GetIndexOf(string hay, string needle, char delimiter)
{
    return Array.FindIndex<string>(hay.Split(delimiter), delegate(string match)
    {
        if (needle.Equals(match.Trim()))
            return true;
        else
            return false;
    });
}

static void Main(string[] args)
{
    StreamReader sr = new StreamReader(Server.MapPath("buildings.txt"));
    using (sr)
    {
        for (string line; null != (line = sr.ReadLine()) && -1 != GetIndexOf(line, "bldgA", ','); )
        {
            Console.WriteLine("You are in bldgA and your name is {0} and your duty is {1}",
                line.Split(',')[GetIndexOf(line, "bldgA", ',') + 1].Trim(),
                line.Split(',')[GetIndexOf(line, "bldgA", ',') + 2].Trim());
        }
    }
}