我有一个文本文件,其中包含如下所示的新行中的人员信息。这个数据包含大约500人。
Person name: abc age: 40 . Person name: xyx age: 18 . Person name: uke age: 27 .
人员信息介于" Person"和"。"字符。我创建了一个Person
类来获取信息:
本文
public class Person {
public string Name { get; set;}
public string Age { get; set;}
}
我想阅读此文本文件并将其解析为Person
类。我可以阅读文件:
string path = @"c:\temp\person.txt";
string readText = File.ReadAllText(path);
但是我无法解析每个人之间的#34; Person"和"。"字符。
我不想使用if else
条件。是否有使用Regex或Split
或LINQ?
我希望在阅读后获得这样的列表:
var person = List<Person> {
new Person { Name = "abc", Age = 40 },
new Person { Name = "xyx", Age = 18 },
new Person { Name = "uke", Age = 27 }
....
...
..
}
答案 0 :(得分:1)
如果使用File.ReadAllLines()
代替.ReadAllText()
,则可以使用装箱功能。我自己写过其中一个,所以如果你想要一些开箱即用的东西(没有双关语)那么你可以安装Anaximander.Linq并像这样使用它:
var readText = File.ReadAllLines(path);
var people = readText
.BoxWhile((a, b) => b != ".")
.Select(x => x
.Where(t => t != "." && t != "Person")
.Select(t => t.Split(':').Last().Trim())
.ToList())
.Where(x => x.Any())
.Select(x => new Person
{
Name = x[0],
Age = x[1]
});
如果您想知道内部如何工作,那么source code is available on GitHub以便您可以了解BoxedEnumerable的实现方式。它使用带有比较运算符的滑动窗口;每当当前元素和下一个元素之间的比较返回false时,它就会启动一个新的“框”。您的问题实际上是我最近看到的几个案例中的一个,其中比较不需要查看当前和下一个,只有下一个,所以我将很快为其添加一个额外的方法。
答案 1 :(得分:1)
您可以按点.
分割文字,为您提供每个人的信息,然后按新行\n
,\r
或\r\n
分割。在你的文件使用什么行结束。然后,您可以从第二行(索引为1)和第三行(索引为2)的年龄获取名称。最后,按冒号和空格": "
拆分名称和年龄,并获取第二个字符串(索引为1)。这假定您的文件结构是固定的并且永远不会更改,否则您需要根据您希望避免的条件找到名称和年龄:
var persons = new List<Person>();
var personInfo = readText.Split(new char[]{'.'}, StringSplitOptions.RemoveEmptyEntries);
foreach (var i in personInfo)
{
var person = new Person();
var lines = i.Split(new char[]{'\n'}, StringSplitOptions.RemoveEmptyEntries);
person.Name = lines[1].Split(new string[]{": "}, StringSplitOptions.None)[1];
person.Age = lines[2].Split(new string[]{": "}, StringSplitOptions.None)[1];
persons.Add(person);
}
或者,您可以使用LINQ:
var persons = readText.Split(new char[]{'.'}, StringSplitOptions.RemoveEmptyEntries)
.Select(i => i.Split(new char[]{'\n'}, StringSplitOptions.RemoveEmptyEntries))
.Select(l => new Person{
Name = l[1].Split(new string[]{": "}, StringSplitOptions.None)[1],
Age = l[2].Split(new string[]{": "}, StringSplitOptions.None)[1]
});
答案 2 :(得分:0)
更容易的替代方案可能是&#34; Person&#34;或&#34;名称:&#34;
List<Person> people = File.ReadAllText(@"c:\temp\person.txt")
.Split(new[] { "name:" }, StringSplitOptions.None)
.Skip(1)
.Select(p => p.Split('\n', ':'))
.Select(a => new Person {
Name = a[0].Trim(),
Age = a[2].Trim()
})
.ToList();
答案 3 :(得分:0)
使用monadic解析器Sprache不是简单但非常强大的解决方案:
您可以组合解析器来解析非常复杂的结构。
<强> SplitTestSample.csproj 强>
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Sprache" Version="2.1.2" />
</ItemGroup>
<强> Program.cs的强>
using System;
using System.Collections.Generic;
using Sprache;
namespace SplitTextSample
{
class Program
{
public static string Text =
@"Person
name: abc
age: 40
.
Person
name: xyx
age: 18
.
Person
name: uke
age: 27
.";
public class Person
{
public string Name { get; set; }
public string Age { get; set; }
}
static void Main(string[] args)
{
// Parses: Person\r\n
var personTagParser = Parse.String("Person").Then(_=>Parse.LineEnd);
// Parses: name: {name}\r\n
Parser<string> nameParser = from tag in Parse.String("name:").Token()
from name in Parse.AnyChar.Except(Parse.LineEnd).AtLeastOnce().Text()
from lineEnd in Parse.LineEnd
select name;
// Parses: age: {age}\r\n.[\r\n]
Parser<string> ageParser = from tag in Parse.String("age:").Token()
from age in Parse.AnyChar.Except(Parse.LineEnd).AtLeastOnce().Text()
from delimeter in Parse.LineEnd.Then(_ => Parse.Char('.')).Then(_=> Parse.LineEnd.Optional())
select age;
// Parses: Person\r\nname: {name}\r\nage: {age}\r\n.[\r\n]
Parser<Person> personParser =
from personTag in personTagParser
from name in nameParser
from age in ageParser
select new Person{Name = name, Age = age};
// Parses: Many persons
var personsParser = personParser.Many();
// Final parse returns IEnumerable<Person>
var persons = personsParser.Parse(Text);
foreach (var person in persons)
{
Console.WriteLine($"Name: {person.Name}, Age: {person.Age}");
}
Console.ReadLine();
}
}
<强>结果:强>
Name: abc, Age: 40
Name: xyx, Age: 18
Name: uke, Age: 27