我该如何解析以下文本文件?

时间:2009-11-18 11:35:18

标签: c# file parsing text

我对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列的列表:名称,地址,身份证。

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

姓名,地址,id_card,城镇,街道

因此,每个公民都必须存放在某种阵列中,阵列将包含公民各自的城镇和公民。

如果有人可以就如何解析这个文本文件的格式给我一些想法,那就太棒了,因为它有一些不寻常的格式。另请注意,姓名,地址和身份证之间的空格是实际的空格而不是标签。

非常感谢提前!

此致 克里斯

6 个答案:

答案 0 :(得分:9)

尝试将问题分解为更小的问题

答案 1 :(得分:1)

您有两种选择:

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

答案 2 :(得分:1)

如果OP可以改变格式会很好,但这并不是一种可能性。

我认为一种方法是......

  1. 生成涵盖所有可能方案的文本文件的大量示例。
  2. 使用它作为指导,为文本结构(或部分文本)构成正则表达式。
  3. 编写解析代码,该代码采用表达式匹配的文本作为输入 - 为您创建的每个正则表达式创建一个。
  4. 将解析后的内容填入任何数据结构中。
  5. 正则表达式是一种廉价而快速的格式验证方法,也是一种“分段”步骤,可以使您的解析器更简单。

答案 3 :(得分:0)

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

答案 4 :(得分:0)

以下是一些可能有助于您入门的代码。我根据数据文件格式做了一些假设:

  1. 人员地址中的每一行都有固定位置的名称,建筑物/公寓和卡片ID。
  2. 此人的姓名是姓名和姓氏(虽然可以处理任意数量的中间名/姓名缩写)
  3. 城镇ID和名称位于第一行
  4. 此人行始终以至少两个空格开头
  5. 空行只是空的
  6. 这有点像黑客,不使用任何正则表达式但是对上面给出的布局示例有效(我假设这些是机器生成的)。代码只是将单个文件解析为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
          };
        }
      }
    }
    

答案 5 :(得分:0)

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

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

公民: ID,姓名,姓氏,IDCard

地址: 身份证,地址,城镇,街道

CitizenAddress: CitizenID,AddressID

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

这给你带来了什么好处?

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

相关问题