【问题标题】:How can I best parse this comma delimited text file?我怎样才能最好地解析这个逗号分隔的文本文件?
【发布时间】:2009-01-15 23:05:51
【问题描述】:

我正在尝试找出解析此逗号分隔文本文件的最佳方法。摘录如下:

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

我要做的是阅读“bldgA”,然后我想要这个人(第二列),例如“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,你的名字是 fred,你的职责是午餐”

【问题讨论】:

  • 我的建议是不要尝试一次性解析它。将其拆分为每个 /bldg?/ 的子列表
  • 您的摘录应放入
     标记中,以便按预期显示。
  • 为什么是 C# 标签?他没有具体说明他希望如何解决这个问题。
  • @Harleqin:我不懂 C#。但是示例代码似乎是用 C# 编写的。
  • @johnny:请说明您使用的语言

标签: parsing csv


【解决方案1】:

如果您知道文件的格式总是正确的,您可以执行以下操作(使用您的代码,假设语言是 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();

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

      【解决方案3】:

      你为什么不使用 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
      

      【讨论】:

        【解决方案4】:

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

        但如果你坚持使用逗号分隔文件,看看这个CsvReader,你可以用它来读取文件。

        【讨论】:

          【解决方案5】:

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

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

          【讨论】:

            【解决方案6】:

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

            bldgA,弗雷德,午餐
            bldgA,莎莉,晚餐
            bldgB,鲍勃,停车场
            bldgB,坦率,屋顶

            获得所需输出的步骤:

            • 读一行
            • 用逗号分割行
            • 使用从 split 函数返回的部分格式化您想要的输出

            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 版本显示了要从运行时使用的函数。也没有输入检查。

            【讨论】:

            • perl -F, -ane'my ($bldg, $name, $duty) = @F; print qq(name: $name, duty: $duty\n) if $bldg =~ /bldg[AB]/'buildings.txt
            【解决方案7】:

            在伪代码中:

            #!/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()) 
            

            【讨论】:

              【解决方案8】:

              请原谅我以这种方式编程,但我认为它可能会解决您的问题。

              我所做的唯一假设是,在 building.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());
                      }
                  }
              }
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2017-03-29
                • 1970-01-01
                • 2013-04-19
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多