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. 获取类型为 HomeUser 的名称
  2. 获取 Address =Germany 的类型(问题在每行中有 3 个地址键)
  3. 获取地址=Lyon的名称

有没有一种简单的方法可以做到这一点?

4

5 回答 5

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>你的查询将非常容易 - 但将“将数据放入更自然的表示”与“对数据进行有趣的操作”分开是很重要的。

这是一个比这个特定示例更笼统的观点,但始终尽可能早地将您的数据转换为自然、有用的表示,然后尽可能长时间地将其保留在该表示中。如果可能,只处理代码边界处的尴尬表示(通常是字符串)。

于 2013-01-31T14:27:44.970 回答
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. 类型是 HomeUser:records.Where(p=>p.Type=="HomeUser")
  2. 地址是德国:records.Where(p=>p.Address=="Germany")
  3. 地址是里昂:records.Where(p=>p.Address=="Lyon")

您可以轻松扩展此示例以查看所有 3 个地址字段

于 2013-01-31T14:28:33.527 回答
0

我认为您可以使用正则表达式将您的标记与反向引用相匹配。

看看这个教程

于 2013-01-31T14:26:45.970 回答
0

首先定义一个结构会更容易

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 */))
}

现在您已经提取了数据并将它们放入结构列表中,您可以使用 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;

或者,您可以这样做:

string tNILF = myStruct.Where(element => element.Type == "HomeUser" /* || etc. */).Select(element => element.Name);
于 2013-01-31T14:52:01.043 回答
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.获取类型为 HomeUser 的名称:

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

2.获取Address =Germany的类型(注:.Address是a List<string>):

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

3.获取地址=Lyon的名称:

var namesInLyon = users.Where(u => u.Address.Contains("Lyon"))
    .Select(u => u.Name);
于 2013-01-31T16:25:40.637 回答