【问题标题】:How can I parse the following text file?如何解析以下文本文件?
【发布时间】:2009-11-18 11:35:17
【问题描述】:

我对 c# 很陌生。有人可以告诉我如何解析以下文本文件的正确方向吗?

我正在尝试实施的程序将执行以下操作:

它会要求用户输入一个目录。 它将在目录中搜索文本文件。 它将遍历文本文件,解析它们,并将它们保存在一个表数据库中。 文本文件具有以下结构:

(这是文本文件 1)

001 - Milan (Citizens)

Pitch Street

  John Doe               15, F1 2             35022I        
  Janette Doe            17, F7 2             32345I            

Angel Street

  Mark Skate             12, F3 2             35532I        
  Jacqueline Skate       18, F6 2             54343I                

(这是文本文件 2)

002 - Rome (Citizens)

Colosseum Street

  Christian Troy         21, F8 5             21354I        
  Janette Doe            17, F7 2             23453T            

Pope Street

  Sean McNamara          Villa McNamara       12424I        
  Julia McNamara         Villa McNamara       43344I                       

等等……

001 - 米兰等...是小镇。这是在每个文本文件的开头找到一次。 斗兽场街等......是街道名称。 然后对于每条街道都有一个包含 3 列的列表:名称、地址、身份证。

我需要将每个公民插入数据库。数据库将有一个具有以下格式的表:

姓名、姓氏、地址、身份证、城镇、街道

因此,每个公民都必须存储在某种数组中,该数组将包含公民各自的城镇和公民。

如果有人能给我一些关于如何解析这个文本文件格式的想法,那就太好了,因为它有一点不寻常的格式。另请注意,姓名、地址和身份证之间的空格是实际空格,而不是制表符。

非常感谢!

问候, 克里斯

【问题讨论】:

    标签: c# file parsing text


    【解决方案1】:

    试着把问题分解成更小的问题

    【讨论】:

    • 感谢教程链接。目前我设法解析了一个包含数千行的文本文件,它看起来不错。
    【解决方案2】:

    你有两个选择:

    1. 一次读一行;第一行是您的城市信息,从第 0 列开始的下一行(没有前导空格)是您的地址,以两个空格开头的行是您的公民信息
    2. 您可以构建一个正则表达式来匹配该文件格式并同时匹配所有文件

    【讨论】:

    • 以3位数字开头的行为城市信息',以字母开头的行为街道名称,以空格开头的行 是公民信息。你可以用正则表达式来做到这一点。
    • @pavium,为您的 cmets 提供帮助;我正在尝试制作一个独特的正则表达式来做到这一点;你能帮忙吗?
    【解决方案3】:

    如果 OP 可以更改格式,那就太好了,但这并不是一种可能性。

    我认为一种方法是...

    1. 生成大量涵盖所有可能场景的文本文件示例。
    2. 以此为指导,为文本(或部分文本)的结构编写正则表达式。
    3. 编写解析代码,将表达式匹配的文本作为输入 - 您创建的每个正则表达式对应一个。
    4. 将解析后的内容填充到任何数据结构中。

    正则表达式可作为一种廉价且快速的方式来验证格式,也可作为“暂存”步骤,使您的解析器更简单。

    【讨论】:

      【解决方案4】:

      您是否被这种文件格式所困扰? (因为这太可怕了!;) 目前,解析器没有明确的方法来区分街道或人。如果您是从头开始创建此文件结构,最好使用 XML,甚至 CSV。

      【讨论】:

      • 对我来说看起来很有条理。
      • 街道没有填充物而人有。
      • 街道也有填充物。这只能基于固定列工作,我不想写一个正则表达式来匹配这个。有些名称将包含 3 个部分。
      • @Lars - 这是我的第一个想法,但文件中没有标签。
      • 仅作记录,当我对此发表评论时,它的结构要少得多(我认为它不在代码块中)。例如,您看不到任何看起来像标签的东西。现在好多了,但仍远未达到理想状态。
      【解决方案5】:

      这里有一些代码可以帮助您入门。我根据数据文件格式做了一些假设:

      1. 个人地址中的每一行在固定位置都有姓名、建筑物/单位和卡号。
      2. 这个人的名字是名字和姓氏(尽管可以处理任意数量的中间名/首字母)
      3. 城镇 ID 和名称在第一行
      4. 人员行始终以至少两个空格开头
      5. 空行就是这样,空的

      这有点小技巧,不使用任何正则表达式,但适用于上面给出的布局示例(我假设这些是机器生成的)。该代码只是将单个文件解析为 Citizen 类,然后您可以将其插入到数据库表中,我假设您知道该怎么做。

      我确信有很多优化,但它可以让你继续前进:

      using System;
      using System.IO;
      
      namespace AddressParser
      {
        class Program
        {
          public class TownInfo
          {
            public int TownID { get; set; }
            public string TownIDAsString { get; set; }
            public string Town { get; set; }
          }
      
          public class Citizen
          {
            public TownInfo Town { get; set; }
            public string Street { get; set; }
            public string FirstName { get; set; }
            public string Surname { get; set; }
            public string Building { get; set; }
            public string Flat { get; set; }
            public string CardID { get; set; }
          }
      
          static void Main(string[] args)
          {
            string dataFile = @"d:\testdata\TextFile1.txt";
      
            ParseAddressFileToDatabase(dataFile);
          }
      
          static void ParseAddressFileToDatabase(string dataFile)
          {
            using(StreamReader sr = new StreamReader(dataFile))
            {
              string line;
              bool isFirstLine = true;
      
              string currentStreet = null;
              TownInfo townInfo = null;
      
              while((line = sr.ReadLine()) != null)
              {
                if(isFirstLine)
                {
                  townInfo = ParseTown(line);
                  isFirstLine = false;
                }
      
                if(line.Trim() == String.Empty)
                  continue;
      
                while(line != null && line.StartsWith("  "))
                {
                  Citizen citizen = ParseCitizen(line, townInfo, currentStreet);
      
                  //
                  // Insert record into DB here
                  //
      
                  line = sr.ReadLine();
                }
      
                currentStreet = line;
              }
            }
          }
      
          private static TownInfo ParseTown(string line)
          {
            string[] town = line.Split('-');
            return new TownInfo()
            {
              TownID = Int32.Parse(town[0].Trim()),
              TownIDAsString = town[0].Trim(),
              Town = town[1].Replace("(Citizens)","").Trim()
            };
          }
      
          private  static Citizen ParseCitizen(string line, TownInfo townInfo, string currentStreet)
          {
            string[] name = line.Substring(2, 23).Trim().Split(' ');
      
            string firstName = name[0];
            string surname = name[name.Length - 1];
      
            // Assumes fixed positions for some fields
            string buildingOrFlat = line.Substring(24, 22).Trim();
            string cardID = line.Substring(46).Trim();
      
            // Split building or flat
            string[] flat = buildingOrFlat.Split(',');
      
            return new Citizen()
            {
              Town = townInfo,
              Street = currentStreet,
              FirstName = firstName,
              Surname = surname,
              Building = flat.Length == 0 ? buildingOrFlat : flat[0],
              Flat = flat.Length == 2 ? flat[1].Trim() : "",
              CardID = cardID
            };
          }
        }
      }
      

      【讨论】:

        【解决方案6】:

        我希望我建议您的数据库结构需要工作还为时不晚(应该有很多答案可以帮助您解决主要问题)。

        您不应该将您的地址存储在您的公民身上 - 您将来会成为一个收割机。相反,有一个单独的表:

        公民: 身份证、姓名、姓氏、身份证

        地址: ID、地址、城镇、街道

        公民地址: CitizenID, AddressID

        因此,您有一个包含公民姓名和身份证详细信息的表,另一个包含地址 - 然后使用“CitizenAddress”表将地址链接到公民。

        这对您有什么好处?

        好吧,如果你在一个地址有两个公民,你只需要存储一次地址。此外,如果您有一个公民可能被列在两个地址的情况,这同样适用。您可以扩展此结构以维护公民在某个时间点居住的历史记录 - 因为您无需在他们移动时覆盖地址。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-06-21
          • 1970-01-01
          • 2020-09-30
          • 1970-01-01
          • 1970-01-01
          • 2011-11-20
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多