我对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,城镇,街道
因此,每个公民都必须存放在某种阵列中,阵列将包含公民各自的城镇和公民。
如果有人可以就如何解析这个文本文件的格式给我一些想法,那就太棒了,因为它有一些不寻常的格式。另请注意,姓名,地址和身份证之间的空格是实际的空格而不是标签。
非常感谢提前!
此致 克里斯
答案 0 :(得分:9)
尝试将问题分解为更小的问题
编写一个测试应用程序,该应用程序将从用户How to browse for folder获取目录
编写一个测试应用程序,它将循环遍历目录中的所有文件Exclude certain file extensions when getting files from a directory
编写一个测试应用程序,一次读取一行文件 https://stackoverflow.com/search?q=c%23+read+lines+in+file
编写一个将解析给定文本的测试应用程序
为此,我将创建一个基于状态的解析器。它知道它接下来要找什么,除非它找到了它,否则它不会移动到下一个状态 - 查找状态机以获得一个想法。如果文件格式的定义与您的示例建议的一样好,那么这将起作用。
答案 1 :(得分:1)
您有两种选择:
答案 2 :(得分:1)
如果OP可以改变格式会很好,但这并不是一种可能性。
我认为一种方法是......
正则表达式是一种廉价而快速的格式验证方法,也是一种“分段”步骤,可以使您的解析器更简单。
答案 3 :(得分:0)
您是否坚持使用此文件格式? (因为它太糟糕了!;)目前,解析器没有明确的方法来区分街道或人。如果您要从头开始创建此文件结构,最好使用XML,甚至CSV。
答案 4 :(得分:0)
以下是一些可能有助于您入门的代码。我根据数据文件格式做了一些假设:
这有点像黑客,不使用任何正则表达式但是对上面给出的布局示例有效(我假设这些是机器生成的)。代码只是将单个文件解析为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”表格将地址链接到公民。
这给你带来了什么好处?
好吧,如果你在一个地址有两个公民,你只需要存储一次地址。此外,如果您有一个公民可能在两个地址列出的情况,同样适用。您可以扩展此结构以维护公民在某个时间点居住的历史记录 - 因为您不需要在移动时覆盖该地址。