2013-01-31 56 views
1

我有一个包含字符串行的文件。每一行代表的关键值的集合,例如:查找字符串中的值

Name=JUI;Type=HomeUser;Address=Belgium;Address=Liege;Address=Street 
Name=Tim;Type=HomeUser;Address=Belgium;Address=Hasselt;Address=Street 
Name=Kim;Type=Proff;Address=Germany;Address=Dusseldorf;Address=Street 
Name=Ils;Type=Proff;Address=Germany;Address=Munich;Address=Street 
Name=Jan;Type=Student;Address=Germany;Address=Frankfurt;Address=Street 
Name=Dav;Type=Student;Address=France;Address=Mitz;Address=Street 
Name=Soli;Type=HomeUser;Address=France;Address=Lyon;Address=Street 
Name=Mik;Type=HomeUser;Address=Switzerland;Address=Zurich;Address=Street 
Name=Peter;Type=Blocked;Address=Netherland;Address=Enschede;Address=Street 
Name=Maz;Type=Blocked;Address=Germany;Address=Achen;Address=Street 
Name=Jo;Type=Teacher;Address=Belgium;Address=Antwerpen;Address=Street 

我怎样才能做到以下几点:

  1. 获取名,其中类型是阅读下面驱动
  2. 获取哪些类型的地址=德国(问题存在于在线操作搜索3地址键)
  3. 获取其中address =里昂

是否有一个名字简单的方法来做到这一点?

+0

有办法这里需要更多的信息,而不仅仅是一堆作业。这些字符串,整数,枚举,类......?这些应该属于一个类的属性吗?如果不知道我们甚至在看什么,绝对没有办法回答这个问题。这些数据如何被拉入C#并被利用? –

+0

我道歉让我对我的意思更简洁。我的意思是可能有100个或更多不同的方法来解析文件中的数据。我的意思是,如果你想在你的特定情况下以最好的方式来做到这一点,那么应该提供关于数据的更多信息,它发生在哪里以及它来自哪里。 –

+0

@LeonNewswanger定义了从日志文件传递到sql表的一些表中的数据。一个例子:我提取所有的用户名** Name =?** 哪里的国家是瑞士的情况下,我在我的帖子中显示我应该得到** Mik **然后更新他在数据库中的记录。我的主要问题是有3个键名**地址** – Maro

回答

4

全部这些情况下,当你有更好的数据表示时,答案很简单 - 你可以使用LINQ。

但是,第一步将解析数据。模型,可以东西这样的:

public class User // ??? 
{ 
    public string Name { get; private set; } 
    public string Type { get; private set; } // Should this be an enum? 
    public IList<string> Addresses { get; private set; } 

    // Could make this a constructor if you really want... I like the 
    // explicit nature of the static factory method. 
    public static User ParseLine(string line) 
    { 
     // TODO: Split line into components etc 
    } 
} 

一个你已经有了一个List<User>你的查询将是很容易 - 但它分开“将数据放入一个更自然的表现”,从“做数据有趣的操作是很重要的”。

这是一个比这个特殊例子更普遍的观点,但总是试图尽可能早地将数据转化为自然,有用的表示形式,然后尽可能长时间地将其保存在表示形式中。如果可能,只处理代码边界处的尴尬表示(通常是字符串)。

+0

谢谢您!还有一个问题,你认为如果在类的文件中为每行创建一个对象用户将会降低应用程序性能或增加内存使用量?让我们说有大约200万行==> 200万个类的用户将被创建 – Maro

+0

@Maro:是的,它会增加内存使用量 - 但如果你从清晰可读的代码开始,它会更容易以后以有针对性的方式进行优化,比如果您编写代码时假设您需要进行优化。你要读多少行?你是否必须一次将所有的值存储在内存中? (例如,也许你可以流式传输它们。) –

+0

我将阅读多个文件总计大约1900万的线路。 我必须处理大多数+/- 95%,其余的将被忽略。 – Maro

0

我认为你可以使用正则表达式来匹配你的标记和反向引用。

看看这个tutorial

3

创建一个正则表达式来解析项目:"Name=(.+?);Type=(.+?);Address=(.+?) etc." 然后,你可以创建一个类来保存所有信息

class Record { public string Name; public string Type; public string Address; public string Address2; public string Address3} 

然后匹配正则表达式的每一行,填补匹配组领域,并创建一个实例并将其添加到List<Record> records

现在你可以很容易地使用LINQ搜索:

  1. 类型阅读下面驱动:records.Where(P =>纸张类型== “阅读下面驱动”)
  2. 地址为德国:records.Where( p => p.Address ==“Germany”)
  3. Address is Lyon:records.Where(p => p。地址==“里昂”)

,你可以轻松地扩展这个例子来看看在所有3个地址字段

0

它会更容易首先定义一个struct

struct MyStruct 
{ 
    public string Name, Type /* etc.*/ ; 
} 

之后,你”会需要现在被你输入

string[] arrayOfInputs = inpuString.Split(new char[]{Environment.NewLine, '\n', '\r'}) // splits your input, such that every element represents a line 
List<MyStruct> myStruct = new List<MyStruct>; 
foreach (string s in arrayOfInputs) 
{ 
    string[] arrayOfFields = s.Split(';'); 
    // arrayOfFields[0] == "Name=name" 
    // arrayOfFields[1] == "Type=type" 
    // etc. extract needed info 
    myStruct.Add(new MyStruct(/* arguments go here */)) 
} 

您已经提取数据,并把它们放到结构的列表,你可以搜索REQ使用LINQ

string theNameImLookingFor = from element in myStruct 
          where element.Type == "HomeUser" 
           || element.Address[0] == "Lyon" 
           || element.Address[1] == "Lyon" 
           || element.Address[2] == "Lyon" 
          select element.Name; 

string theTypeImLookingFor = from element in myStruct 
          // etc. 
          select element.Type; 

uired数据或者你可以做这样的:

string tNILF = myStruct.Where(element => element.Type == "HomeUser" /* || etc. */).Select(element => element.Name); 
+0

想象我有200万行,如果我为每一行创建一个结构,那么我必须根据我的信息升级服务器内存:-)结构是值类型:-) – Maro

+0

@Maro在这种情况下,最好只处理一个一次一行,因此LINQ变得毫无用处。为了得到每一行,你将使用Regex'foreach(匹配匹配Regex.Matches(输入,@“name =。+?((?= name =)| $)”,RegexOptions.IgnoreCase)){/ * match.Value包含一行,可以用';'分隔以获得每个字段* /}'但是,如果正则表达式不符合预期,调试将成为一大痛苦。你被警告了 ;) – Nolonar

0

一种方式做,这是读键值对为动态对象的集合。一旦做到这一点,你可以使用动态运行时使用LINQ查询动态对象:

创建动态对象的集合:

var users = str.Split("\r\n".ToArray(), StringSplitOptions.RemoveEmptyEntries) 
       .Select(x => x.Split(';') 
        .Select(p => p.Split('=')) 
        .ToLookup(s => s[0], s => s[1]) 
        .ToDictionary(l => l.Key, l => (l.Count() > 1) 
         ? (object)l.ToList() : (object)l.First()) 
        .ToExpando()); 

注意使用这个扩展的方法:

public static dynamic ToExpando(this IDictionary<string, object> dict) 
{ 
    IDictionary<string, object> expando = new ExpandoObject(); 
    foreach (var kv in dict) 
     expando[kv.Key] = kv.Value; 
    return expando; 
} 

然后你可以运行查询你感兴趣的:

1.Get其中类型是在阅读下面驱动名称:

var homeUsers = users.Where(u => u.Type == "HomeUser") 
    .Select(u => u.Name); 

2.注册地址在那里德国=类型(注:.AddressList<string>):

var typesInGermany = users.Where(u=>u.Address.Contains("Germany")) 
    .Select(u => u.Type).Distinct(); 

3.Get的名称,其中地址=里昂:

var namesInLyon = users.Where(u => u.Address.Contains("Lyon")) 
    .Select(u => u.Name);