[C#] Linq To Objects - 如何操作字符串
Linq To Objects - 如何操作字符串
开篇语:
上次发布的 《LINQ:进阶 - LINQ 标准查询操作概述》(90+赞) 社会反响不错,但自己却始终觉得缺点什么!“纸上得来终觉浅,绝知此事要躬行”,没错,就是实战!这次让我们一起来看看一些操作字符串的技巧,也许能引我们从不同的角度思考问题,从而走出思维的死角!
序
LINQ 可用于查询和转换字符串和字符串集合。它对文本文件中的半结构化数据尤其有用。LINQ 查询可与传统的字符串函数和正则表达式结合使用。
查询文本块
查询文本格式的半结构化数据
一、如何统计单词在字符串出现次数
const string text = @"Historically, the world of data and the world of objects" +
@" have not been well integrated. Programmers work in C# or Visual Basic" +
@" and also in SQL or XQuery. On the one side are concepts such as classes," +
@" objects, fields, inheritance, and .NET Framework APIs. On the other side" +
@" are tables, columns, rows, nodes, and separate languages for dealing with" +
@" them. Data types often require translation between the two worlds; there are" +
@" different standard functions. Because the object world has no notion of query, a" +
@" query can only be represented as a string without compile-time type checking or" +
@" IntelliSense support in the IDE. Transferring data from SQL tables or XML trees to" +
@" objects in memory is often tedious and error-prone."; const string searchTerm = "data"; //字符串转换成数组
var source = text.Split(new[] { '.', '?', '!', ' ', ';', ':', ',' }, StringSplitOptions.RemoveEmptyEntries); //创建查询,并忽略大小写比较
var matchQuery = from word in source
where string.Equals(word, searchTerm, StringComparison.InvariantCultureIgnoreCase)
select word; //统计匹配数量
var wordCount = matchQuery.Count();
Console.WriteLine($"{wordCount} occurrences(s) of the search term \"{searchTerm}\" were found.");
二、如何查询包含指定的一组单词的句子
const string text = @"Historically, the world of data and the world of objects " +
@"have not been well integrated. Programmers work in C# or Visual Basic " +
@"and also in SQL or XQuery. On the one side are concepts such as classes, " +
@"objects, fields, inheritance, and .NET Framework APIs. On the other side " +
@"are tables, columns, rows, nodes, and separate languages for dealing with " +
@"them. Data types often require translation between the two worlds; there are " +
@"different standard functions. Because the object world has no notion of query, a " +
@"query can only be represented as a string without compile-time type checking or " +
@"IntelliSense support in the IDE. Transferring data from SQL tables or XML trees to " +
@"objects in memory is often tedious and error-prone."; //将文本块切割成数组
var sentences = text.Split('.', '?', '!'); //定义搜索条件,此列表可以运行时动态添加
string[] wordsToMatch = { "Historically", "data", "integrated" }; var match = from sentence in sentences
let t =
sentence.Split(new char[] { '.', '?', '!', ' ', ';', ':', ',' }, StringSplitOptions.RemoveEmptyEntries)
where t.Distinct().Intersect(wordsToMatch).Count() == wordsToMatch.Length //去重,取交集后的数量对比
select sentence; foreach (var s in match)
{
Console.WriteLine(s);
}
查询运行时首先将文本拆分成句子,然后将句子拆分成包含每个单词的字符串数组。对于每个这样的数组,Distinct<TSource> 方法移除所有重复的单词,然后查询对单词数组和 wordstoMatch 数组执行 Intersect<TSource> 操作。如果交集的计数与 wordsToMatch 数组的计数相同,则在单词中找到了所有的单词,且返回原始句子。
三、如何在字符串中查询字符
因为 String 类实现泛型 IEnumerable<T> 接口,所以可以将任何字符串作为字符序列进行查询。但是,这不是 LINQ 的常见用法。若要执行复杂的模式匹配操作,请使用 Regex 类。
下面的示例查询一个字符串以确定它包含的数字的数目。
const string aString = "ABCDE99F-J74-12-89A";
//只选择数字的字符
var digits = from ch in aString
where char.IsDigit(ch)
select ch;
Console.Write("digit: ");
foreach (var n in digits)
{
Console.Write($"{n} ");
}
Console.WriteLine();
//选择第一个“-”之前的所有字符
var query = aString.TakeWhile(x => x != '-');
foreach (var ch in query)
{
Console.Write(ch);
}

四、如何用正则表达式结合 LINQ 查询
此示例演示如何使用 Regex 类创建正则表达式以便在文本字符串中进行更复杂的匹配。使用 LINQ 查询可以方便地对您要用正则表达式搜索的文件进行准确筛选,以及对结果进行加工。
//根据不同版本的 vs 修改路径
const string floder = @"C:\Program Files (x86)\Microsoft Visual Studio 14.0\";
var infoes = GetFiles(floder);
//创建正则表达式来寻找所有的"Visual"
var searchTerm = new Regex(@"Visual (Basic|C#|C\+\+|J#|SourceSafe|Studio)"); //搜索每一个“.html”文件
//通过 where 找到匹配项
//【注意】select 中的变量要求显示声明其类型,因为 MatchCollection 不是泛型 IEnumerable 集合
var query = from fileInfo in infoes
where fileInfo.Extension == ".html"
let text = File.ReadAllText(fileInfo.FullName)
let matches = searchTerm.Matches(text)
where matches.Count >
select new
{
name = fileInfo.FullName,
matchValue = from Match match in matches select match.Value
}; Console.WriteLine($"The term \"{searchTerm}\" was found in:"); foreach (var q in query)
{
//修剪匹配找到的文件中的路径
Console.WriteLine($"{q.name.Substring(floder.Length - 1)}"); //输出找到的匹配值
foreach (var v in q.matchValue)
{
Console.WriteLine(v);
}
}
private static IList<FileInfo> GetFiles(string path)
{
var files = Directory.GetFiles(path, "*.*", SearchOption.AllDirectories); return files.Select(file => new FileInfo(file)).ToList();
}

您还可以查询由 RegEx 搜索返回的 MatchCollection 对象。在此示例中,结果中仅生成每个匹配项的值。但也可使用 LINQ 对该集合执行各种筛选、排序和分组操作。
【注意】由于 MatchCollection 是非泛型 IEnumerable 集合,因此必须显式声明查询中的范围变量的类型。
五、如何查找两个集合间的差异
Bankov, Peter
Holm, Michael
Garcia, Hugo
Potra, Cristina
Noriega, Fabricio
Aw, Kam Foo
Beebe, Ann
Toyoshima, Tim
Guy, Wey Yuan
Garcia, Debra
names1.txt
Liu, Jinghao
Bankov, Peter
Holm, Michael
Garcia, Hugo
Beebe, Ann
Gilchrist, Beth
Myrcha, Jacek
Giakoumakis, Leo
McLin, Nkenge
El Yassir, Mehdi
names2.txt

//创建数据源
var names1Text = File.ReadAllLines(@"names1.txt");
var names2Text = File.ReadAllLines(@"names2.txt"); //创建查询,这里必须使用方法语法
var query = names1Text.Except(names2Text); //执行查询
Console.WriteLine("The following lines are in names1.txt but not names2.txt");
foreach (var name in query)
{
Console.WriteLine(name);
}
六、如何排序或过滤任意单词或字段的文本数据
, , , ,
, , , ,
, , , ,
, , , ,
, , , ,
, , , ,
, , , ,
, , , ,
, , , ,
, , , ,
, , , ,
, , , ,
scores.csv
//创建数据源
var scores = File.ReadAllLines(@"scores.csv");
//可以改为 0~4 的任意值
const int sortField = ; //演示从方法返回查询
//返回查询变量,非查询结果
//这里执行查询
foreach (var score in RunQuery(scores, sortField))
{
Console.WriteLine(score);
}
private static IEnumerable<string> RunQuery(IEnumerable<string> score, int num)
{
//分割字符串来排序
var query = from line in score
let fields = line.Split(',')
orderby fields[num] descending
select line; return query;
}
此示例还演示如何从方法返回查询变量。
七、如何对一个分割的文件的字段重新排序
逗号分隔值 (CSV) 文件是一种文本文件,通常用于存储电子表格数据或其他由行和列表示的表格数据。通过使用 Split 方法分隔字段,可以非常轻松地使用 LINQ 来查询和操作 CSV 文件。事实上,可以使用此技术来重新排列任何结构化文本行部分;此技术不局限于 CSV 文件。
Adams,Terry,
Fakhouri,Fadi,
Feng,Hanying,
Garcia,Cesar,
Garcia,Debra,
Garcia,Hugo,
Mortensen,Sven,
O'Donnell,Claire,112
Omelchenko,Svetlana,
Tucker,Lance,
Tucker,Michael,
Zabokritski,Eugene,
spreadsheet1.csv
//数据源
var lines = File.ReadAllLines(@"spreadsheet1.csv");
//将旧数据的第2列的字段放到第一位,逆向结合第0列和第1列的字段
var query = from line in lines
let t = line.Split(',')
orderby t[]
select $"{t[2]}, {t[1]} {t[0]}"; foreach (var q in query)
{
Console.WriteLine(q);
} //写入文件
File.WriteAllLines("spreadsheet2.csv", query);

八、如何组合和比较字符串集合
此示例演示如何合并包含文本行的文件,然后排序结果。具体来说,此示例演示如何对两组文本行执行简单的串联、联合和交集。
Bankov, Peter
Holm, Michael
Garcia, Hugo
Potra, Cristina
Noriega, Fabricio
Aw, Kam Foo
Beebe, Ann
Toyoshima, Tim
Guy, Wey Yuan
Garcia, Debra
names1.txt
Liu, Jinghao
Bankov, Peter
Holm, Michael
Garcia, Hugo
Beebe, Ann
Gilchrist, Beth
Myrcha, Jacek
Giakoumakis, Leo
McLin, Nkenge
El Yassir, Mehdi
names2.txt
var names1Text = File.ReadAllLines(@"names1.txt");
var names2Text = File.ReadAllLines(@"names2.txt"); //简单连接,并排序。重复保存。
var concatQuery = names1Text.Concat(names2Text).OrderBy(x => x);
OutputQueryResult(concatQuery, "Simple concatenate and sort. Duplicates are preserved:"); //基于默认字符串比较器连接,并删除重名。
var unionQuery = names1Text.Union(names2Text).OrderBy(x => x);
OutputQueryResult(unionQuery, "Union removes duplicate names:"); //查找在两个文件中出现的名称
var intersectQuery = names1Text.Intersect(names2Text).OrderBy(x => x);
OutputQueryResult(intersectQuery, "Merge based on intersect:"); //在每个列表中找到匹配的字段。使用 concat 将两个结果合并,然后使用默认的字符串比较器进行排序
const string nameMatch = "Garcia";
var matchQuery1 = from name in names1Text
let t = name.Split(',')
where t[] == nameMatch
select name;
var matchQuery2 = from name in names2Text
let t = name.Split(',')
where t[] == nameMatch
select name; var temp = matchQuery1.Concat(matchQuery2).OrderBy(x => x);
OutputQueryResult(temp, $"Concat based on partial name match \"{nameMatch}\":");
private static void OutputQueryResult(IEnumerable<string> querys, string title)
{
Console.WriteLine(Environment.NewLine + title);
foreach (var query in querys)
{
Console.WriteLine(query);
} Console.WriteLine($"{querys.Count()} total names in list");
}


九、如何从多个源中填充对象集合
//每行 names.csv 包含姓氏,名字,和身份证号,以逗号分隔。例如,Omelchenko,Svetlana,111
var names = File.ReadAllLines(@"names.csv");
//每行 scores.csv 包括身份证号码和四个测试评分,以逗号分隔。例如,111,97,92,81,60
var scores = File.ReadAllLines(@"scores.csv"); //使用一个匿名的类型合并数据源。
//【注意】动态创建一个 int 的考试成绩成员列表。
//跳过分割字符串中的第一项,因为它是学生的身份证,不是一个考试成绩
var students = from name in names
let t = name.Split(',')
from score in scores let t2 = score.Split(',')
where t[] == t2[]
select new
{
FirstName = t[],
LastName = t[],
ID = Convert.ToInt32(t[]),
ExamScores = (from scoreAsText in t2.Skip()
select Convert.ToInt32(scoreAsText)).ToList()
}; foreach (var student in students)
{
Console.WriteLine(
$"The average score of {student.FirstName} {student.LastName} is {student.ExamScores.Average()}.");
}
十、如何使用 group 将一个文件拆分成多个文件
Bankov, Peter
Holm, Michael
Garcia, Hugo
Potra, Cristina
Noriega, Fabricio
Aw, Kam Foo
Beebe, Ann
Toyoshima, Tim
Guy, Wey Yuan
Garcia, Debra
names1.txt
Liu, Jinghao
Bankov, Peter
Holm, Michael
Garcia, Hugo
Beebe, Ann
Gilchrist, Beth
Myrcha, Jacek
Giakoumakis, Leo
McLin, Nkenge
El Yassir, Mehdi
names2.txt
var fileA = File.ReadAllLines(@"names1.txt");
var fileB = File.ReadAllLines(@"names2.txt"); //并集:连接并删除重复的名字
var mergeQuery = fileA.Union(fileB);
//根据姓氏的首字母对姓名进行分组
var query = from name in mergeQuery
let t = name.Split(',')
group name by t[][] into g
orderby g.Key
select g; //注意嵌套的 foreach 循环
foreach (var g in query)
{
var fileName = @"testFile_" + g.Key + ".txt";
Console.WriteLine(g.Key + ":"); //写入文件
using (var sw = new StreamWriter(fileName))
{
foreach (var name in g)
{
sw.WriteLine(name);
Console.WriteLine(" " + name);
}
}
}

十一、如何向不同的文件中加入内容
, , , ,
, , , ,
, , , ,
, , , ,
, , , ,
, , , ,
, , , ,
, , , ,
, , , ,
, , , ,
, , , ,
, , , ,
scores.csv
Omelchenko,Svetlana,
O'Donnell,Claire,112
Mortensen,Sven,
Garcia,Cesar,
Garcia,Debra,
Fakhouri,Fadi,
Feng,Hanying,
Garcia,Hugo,
Tucker,Lance,
Adams,Terry,
Zabokritski,Eugene,
Tucker,Michael,
names.csv
scores.csv:此文件表示电子表格数据。第 1 列是学生的 ID,第 2 至 5 列是测验分数。
names.csv:此文件表示一个电子表格。该电子表格包含学生的姓氏、名字和学生 ID。
var names = File.ReadAllLines(@"names.csv");
var scores = File.ReadAllLines(@"scores.csv"); //Name: Last[0], First[1], ID[2]
// Omelchenko, Svetlana, 11
//Score: StudentID[0], Exam1[1] Exam2[2], Exam3[3], Exam4[4]
// 111, 97, 92, 81, 60 //该查询基于 id 连接两个不同的电子表格
var query = from name in names
let t1 = name.Split(',')
from score in scores
let t2 = score.Split(',')
where t1[] == t2[]
orderby t1[]
select $"{t1[0]},{t2[1]},{t2[2]},{t2[3]},{t2[4]}"; //输出
OutputQueryResult(query, "Merge two spreadsheets:");
private static void OutputQueryResult(IEnumerable<string> querys, string title)
{
Console.WriteLine(Environment.NewLine + title);
foreach (var query in querys)
{
Console.WriteLine(query);
} Console.WriteLine($"{querys.Count()} total names in list");
}

十二、如何计算一个 CSV 文本文件中的列值
, , , ,
, , , ,
, , , ,
, , , ,
, , , ,
, , , ,
, , , ,
, , , ,
, , , ,
, , , ,
, , , ,
, , , ,
scores.csv
scores.csv:假定第一列表示学员 ID,后面几列表示四次考试的分数。
var scores = File.ReadAllLines(@"scores.csv");
//指定要计算的列
const int examNum = ;
//scores.csv 格式:
//Student ID Exam#1 Exam#2 Exam#3 Exam#4
//111, 97, 92, 81, 60
//+1 表示跳过第一列
//计算但一列
SingleColumn(scores, examNum+);
Console.WriteLine();
//计算多列
MultiColumns(scores);
private static void SingleColumn(IEnumerable<string> strs, int examNum)
{
Console.WriteLine("Single Column Query:"); //查询分两步:
// 1.分割字符串
// 2.对要计算的列的值转换为 int
var query = from str in strs
let t = str.Split(',')
select Convert.ToInt32(t[examNum]); //对指定的列进行统计
var average = query.Average();
var max = query.Max();
var min = query.Min(); Console.WriteLine($"Exam #{examNum}: Average:{average:##.##} High Score:{max} Low Score:{min}");
} private static void MultiColumns(IEnumerable<string> strs)
{
Console.WriteLine("Multi Column Query:"); //查询步骤:
// 1.分割字符串
// 2.跳过 id 列(第一列)
// 3.将当前行的每个评分都转换成 int,并选择整个序列作为一行结果。
var query = from str in strs
let t1 = str.Split(',')
let t2 = t1.Skip()
select (from t in t2
select Convert.ToInt32(t)); //执行查询并缓存结果以提高性能
var results = query.ToList();
//找出结果的列数
var count = results[].Count(); //执行统计
//为每一列分数的循环执行一次循环
for (var i = ; i < count; i++)
{
var query2 = from result in results
select result.ElementAt(i); var average = query2.Average();
var max = query2.Max();
var min = query2.Min(); //+1 因为 #1 表示第一次考试
Console.WriteLine($"Exam #{i + 1} Average: {average:##.##} High Score: {max} Low Score: {min}");
} }
查询的工作原理是使用 Split 方法将每一行文本转换为数组。每个数组元素表示一列。最后,每一列中的文本都转换为其数字表示形式。如果文件是制表符分隔文件,只需将 Split 方法中的参数更新为 \t。
================================================== 传送门分割线 ==================================================
LINQ 其它随笔 - 《开始使用 LINQ》
================================================== 传送门分割线 ==================================================
【首联】http://www.cnblogs.com/liqingwen/p/5814204.html
【参考】https://msdn.microsoft.com/zh-cn/library/bb397915(v=vs.100).aspx
[C#] Linq To Objects - 如何操作字符串的更多相关文章
- [C#] Linq To Objects - 如何操作文件目录
Linq To Objects - 如何操作文件目录 开篇语: 上次发布的 <LINQ:进阶 - LINQ 标准查询操作概述> 社会反响不错,但自己却始终觉得缺点什么!“纸上得来终觉浅,绝 ...
- C# LINQ学习笔记三:LINQ to OBJECT之操作字符串
本笔记摘抄自:https://www.cnblogs.com/liqingwen/p/5814204.html,记录一下学习过程以备后续查用. 一.统计单词在字符串中出现的次数 请注意,若要执行计数, ...
- Linq之旅:Linq入门详解(Linq to Objects)
示例代码下载:Linq之旅:Linq入门详解(Linq to Objects) 本博文详细介绍 .NET 3.5 中引入的重要功能:Language Integrated Query(LINQ,语言集 ...
- Linq To Objects
一.什么是Linq To Objects 从根本上说,Linq To Objects表示一种新的处理集合的方法.采用旧方法,必须编写指定如何从集合检索数据的复杂的foreach循环.而采用Linq方法 ...
- LINQ to Objects系列(1)相关技术准备
LINQ to Objects是LINQ的一部分,是查询对象集合的一种语法.首先看一下LINQ的体系结构,这样对LINQ有一个大致的了解.如图. 第一篇文章主要是回顾一下学习LINQ to Objec ...
- LinQ实战学习笔记(一) LINQ to (Objects, XML, SQL) 入门初步
LINQ对于笔者来说, 优美而浓缩的代码让人震惊. 研究LINQ就是在艺术化自己的代码. 之前只是走马观花学会了基本的语法, 但是经常在CSDN看到令人惊讶自叹不如的LINQ代码, 还是让人羡慕嫉妒恨 ...
- Linq之旅:Linq入门详解(Linq to Objects)【转】
http://www.cnblogs.com/heyuquan/p/Linq-to-Objects.html Linq之旅:Linq入门详解(Linq to Objects) 示例代码下载:Linq之 ...
- Linq之旅:Linq入门详解(Linq to Objects)(转)
http://www.cnblogs.com/heyuquan/p/Linq-to-Objects.html 示例代码下载:Linq之旅:Linq入门详解(Linq to Objects) 本博文详细 ...
- LINQ to Entities 和LINQ to Objects 的区别
本文资料来源:http://www.codeproject.com/Articles/246861/LINQ-to-Entities-Basic-Concepts-and-Features) LINQ ...
随机推荐
- Javascript生成二维码(QR)
网络上已经有非常多的二维码编码和解码工具和代码,很多都是服务器端的,也就是说需要一台服务器才能提供二维码的生成.本着对服务器性能的考虑,这种小事情都让服务器去做,感觉对不住服务器,尤其是对于大流量的网 ...
- Matlab 高脚杯模型切片
前言:此文为去年我替人做的一个课题,觉得比较简洁,图形也比较美观,因此放在博文里 数据源我放到了百度云盘高脚杯数据源 有兴趣的可以下载数据,跑程序试一下.也可以单独看看代码,看下实现过程. 主函数 % ...
- IL异常处理
异常处理在程序中也算是比较重要的一部分了,IL异常处理在C#里面实现会用到一些新的方法 1.BeginExceptionBlock:异常块代码开始,相当于try,但是感觉又不太像 2.EndExcep ...
- SAP CRM 性能小技巧
导言 本页面打算收集SAP CRM实施中可以用于避免性能问题的注意事项,重要的事项会由图标标识. 如果你有其他的技巧想要说出来,别犹豫! 性能注意事项 通用 缓存读取类访问,特别是在性能关键的地方,比 ...
- Android Studio 编译单个module
前期自己要把gradle环境变量配置好 在Terminal中gradle命令行编译apk 输入gradle assembleRelease 会编译全部module编译单个modulecd ./xiru ...
- 嵌入式&iOS:回调函数(C)与block(OC)传 参/函数 对比
C的回调函数: callBack.h 1).声明一个doSomeThingCount函数,参数为一个(无返回值,1个int参数的)函数. void DSTCount(void(*CallBack)(i ...
- IOS之Objective-C学习 ARC下的单例模式
单例模式是我常用的一种设计模式,最常见的用途就是用来保存数据并且传递数据.这都归功于单例模式的特性,首先就让我为大家简单介绍一下单例模式的特性. 单例模式的三大特性: 1.某个类只能有一个实例: 2. ...
- Linux设备管理(四)_从sysfs回到ktype
sysfs是一个基于ramfs的文件系统,在2.6内核开始引入,用来导出内核对象(kernel object)的数据.属性到用户空间.与同样用于查看内核数据的proc不同,sysfs只关心具有层次结构 ...
- linux常用命令(2)pwd命令
pwd 命令1 命令格式:pwd [选项]2 命令功能查看当前工作目录的完整路径3 常用参数一般不带任何参数如果目录是链接时:pwd -P 显示实际路径,而非使用链接路径4 常用实例:4.1 用pwd ...
- Openfire的启动过程与session管理
说明 本文源码基于Openfire4.0.2. Openfire的启动 Openfire的启动过程非常的简单,通过一个入口初始化lib目录下的openfire.jar包,并启动一个 ...