在字符串中查找值
本文关键字:查找 字符串 | 更新日期: 2023-09-27 17:57:03
我有一个带有字符串行的文件。每行表示键值的集合,例如:
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
我该如何执行以下操作:
- 获取类型为"家庭用户"的名称
- 获取地址=德国的类型(问题有3个地址键在耳边行)
- 获取地址 =里昂
有没有简单的方法可以做到这一点?
在所有这些情况下,当您获得更好的数据表示形式时,答案非常简单 - 您只需使用 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>
您的查询将非常简单 - 但重要的是要将"将数据放入更自然的表示形式"与"对数据进行有趣的操作"分开。
这是一个比这个特定示例更普遍的观点,但始终尝试尽早将数据转换为自然、有用的表示形式,然后尽可能长时间地将其保留在该表示形式中。如果可能,只处理代码边界处的尴尬表示形式(通常是字符串)。
创建一个正则表达式来解析项目:"Name=(.+?);Type=(.+?);Address=(.+?) etc."
然后,您可以创建一个类来保存所有信息
class Record { public string Name; public string Type; public string Address; public string Address2; public string Address3}
然后将每一行与正则表达式匹配,填写 Match 组中的字段并创建类的实例并将其添加到List<Record> records
中。
现在,您可以使用 linq 轻松搜索:
- 类型为家庭用户:记录。其中(p=>p.Type=="HomeUser")
- 地址是德国:记录。其中(p=>p.Address=="德国")
- 地址是里昂:记录。其中(p=>p.Address=="Lyon")
您可以轻松地扩展此示例以查找所有 3 个地址字段
首先定义一个结构会更容易
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);
一种方法是将键值对读入动态对象的集合中。完成此操作后,可以使用动态运行时使用 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.获取类型为家庭用户的名称:
var homeUsers = users.Where(u => u.Type == "HomeUser")
.Select(u => u.Name);
2.获取地址=德国的类型(注意:.Address
是List<string>
):
var typesInGermany = users.Where(u=>u.Address.Contains("Germany"))
.Select(u => u.Type).Distinct();
3.获取地址 =里昂的名称:
var namesInLyon = users.Where(u => u.Address.Contains("Lyon"))
.Select(u => u.Name);