score:1
You can split the text by the dots .
which gives you the info for each person, then split each by new lines \n
, \r
, or \r\n
depending on what line-ending your files uses. You can then get the name from the second line (with index 1) and the age from the third line (with index 2). Finally, split the name and age by colon and space ": "
and get the second string (with index 1). This assumes that your file structure is fixed and never changes, otherwise you'll need find the name and age based on conditions which you said you wanted to avoid:
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);
}
Alternatively, you can use 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]
});
score:1
If you use File.ReadAllLines()
instead of .ReadAllText()
, then you can use a boxing function. I've written one of these myself, so if you want something that works out of the box (no pun intended) then you can install Anaximander.Linq and use it like this:
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]
});
If you want to know how this works internally, then the source code is available on GitHub so you can take a look at how BoxedEnumerable is implemented. It uses a sliding window with a comparison operator; it starts a new "box" each time the comparison between the current element and the next returns false. Your question is actually one of several cases I've seen recently where the comparison doesn't need to look at the current and next, only the next, so I'll be adding an additional method for that shortly.
score:0
Easier alternative might be to split by "Person" or "name:"
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();
score:0
Not simple but very powerfull solution using monadic parser Sprache:
You can combine parsers to parse very complex structures.
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();
}
}
Result:
Name: abc, Age: 40
Name: xyx, Age: 18
Name: uke, Age: 27
Source: stackoverflow.com
Related Articles
- How do I find the text within a div in the source of a web page using C#
- Entity Framework, Code First and Full Text Search
- LINQ Source Code Available
- .NET 4 Code Contracts: "requires unproven: source != null"
- Is there a cleaner way to split delimited text into data structures?
- creating Linq to sqlite dbml from DbLinq source code
- Code Cleanup: Best way to split long statement over multiple lines
- How to split periodic text?
- source code for LINQ 101 samples
- Split text with string
- List or Array of String Contain specific word in Html Source Code
- How do I split the comma separated string in my text file and save each string in different variable?
- how to split json data and set related data to their related html text by ajax
- c# Linq or code to extract groups from a single list of source data
- Linq Find Partial Text Match - Included code returns duplicate and everything except what it should
- Split information from a database-column to Text and Numbers
- Split List into Sublists with LINQ
- Convert string[] to int[] in one line of code using LINQ
- Code equivalent to the 'let' keyword in chained LINQ extension method calls
- Value cannot be null. Parameter name: source
- Split a collection into `n` parts with LINQ?
- Linq code to select one item
- C# - code to order by a property using the property name as a string
- Roslyn failed to compile code
- Can I split an IEnumerable into two by a boolean criteria without two queries?
- Is it possible to use Full Text Search (FTS) with LINQ?
- Entity-framework code is slow when using Include() many times
- The data source does not support server-side data paging
- How are people unit testing code that uses Linq to SQL
- Split an IEnumerable<T> into fixed-sized chunks (return an IEnumerable<IEnumerable<T>> where the inner sequences are of fixed length)
- How do I select rows into columns?
- Linq, using ToLookup to project values to different named variables
- How to return all elements matching field in a List<Foo>?
- Linq - Sort list of objects by several contained properties
- How to select distinct employees with LINQ based on ID from an employee collection where employee 's salary is 2nd highest?
- Linq Query from textboxes that might be empty (Coalesce)
- Why doesn't Visual Studio 2010 allow the use of "is null" in a linq query when VS2017 does?
- Is there a way I could change a LINQ query orderBy depending on a parameter?
- Error with lazy loading in Entity Framework Entity
- How to check if properties of two objects are equal
- how to search Year between in Dynamic Linq
- Take list of unique by name Presidents with the oldest date of Governance (if name repeated)
- How to get moving combination from two List<String> in C#?
- Why is LINQ not purely functional?
- Creating a generic method in IEnumerable
- Build LINQ queries dynamically - force using sp_executesql instead of raw query
- Update Linq To Entities
- Linq query has an implicit cast error for DataGridViewRow when option strict is enabled
- Using LINQ to build Hierarchical Navigation for Repeater
- How to make a groupped linq Query like a flat table