LINQ 替换不同的字符串值
LINQ Replace Different String Values
我通过解析包含一些地址的文本文件构造了一个变量。
FileInfo fi = new FileInfo(@"C:\temp\Addresses.txt")
var ZipCodesAndCountryCodes = File.ReadLines(fi.FullName)
.Select(l => new
{
ZipCode = l.Substring(1395, 5),
CountryCode = String.IsNullOrWhiteSpace(l.Substring(1405,30))
? "US"
: l.Substring(1405,30)
});
在此代码中,我将国家/地区的任何空白值替换为 "US"。但是,如果国家/地区是 "United States" 或 "United States of America" 或 "USA",我也想将其标准化为 "US"。我怎样才能在 LINQ 中做到这一点?如果是任何其他国家/地区,则应按原样包括在内。
速度也是一个考虑因素,因为我要解析的文本文件将有 800MB 左右。感谢您的帮助。
更新 1:
当我尝试 Mark 和 Aush 的回答时出现此错误:
System.ObjectDisposedException: Cannot read from a closed TextReader.
at System.IO.__Error.ReaderClosed()
at System.IO.StreamReader.ReadLine()
at System.IO.File.<InternalReadLines>d__0.MoveNext()
at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
at System.Linq.Lookup`2.Create[TSource](IEnumerable`1 source, Func`2 keySelector, Func`2 elementSelector, IEqualityComparer`1 comparer)
at System.Linq.GroupedEnumerable`3.GetEnumerator()
at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
at AnthemMDTS.Program.Main(String[] args) in c:\Projects\CustomerA\CustomerATax\Program.cs:line 100
这里提到的 TextReader 是什么?我没有关闭任何东西,代码中也没有任何循环。
FileInfo fi = new FileInfo(@"C:\temp\Addresses.txt")
var ZipCodesAndCountryCodes = File.ReadLines(fi.FullName).Select(l =>
{
var countrySubstr = l.Substring(1405,30);
return new
{
ZipCode = l.Substring(1395, 5),
CountryCode = string.IsNullOrWhiteSpace(countrySubstr)
|| countrySubstr == "USA"
|| countrySubstr == "United States"
|| countrySubstr == "United States of America"
? "US" : countrySubstr
};
});
您可以在查询表达式中使用 let
子句来存储国家名称 Substring()
的结果。
var ZipCodesAndCountryCodes = from line in File.ReadLines(fi.FullName)
let country = line.Substring(1405,30)
select new
{
ZipCode = line.Substring(1395, 5),
CountryCode = ( string.IsNullOrWhiteSpace(country)
|| country=="United States"
|| country=="United States of America"
|| country=="USA")
? "US"
: country
};
string[] textToSearch = new []{"US","United States","United States of America", "USA"};
FileInfo fi = new FileInfo(@"C:\temp\Addresses.txt")
var ZipCodesAndCountryCodes = File.ReadLines(fi.FullName).Select(l => new
{
ZipCode = l.Substring(1395, 5),
CountryCode = (string.IsNullOrWhiteSpace(l.Substring(1405,30)
|| textToSearch.Contains(l.Substring(1405,30))
? "US"
: l.Substring(1405,30)
});
我可能会使用 GroupJoin
本质上 LEFT OUTER JOIN
具有预定义映射的值。
Dictionary<string, string> mappings = new Dictionary<string, string>()
{
{ "United States", "US" },
{ "United States of America", "US" },
{ "USA", "US" }
};
return ZipCodesAndCountryCodes
.GroupJoin(mappings,
a => a.CountryCode,
b => b.Key,
(a, b) => new {
a.ZipCode,
CountryCode = b.Select(x => x.Value).FirstOrDefault() ?? a.CountryCode
},
StringComparer.CurrentCultureIgnoreCase);
这使您可以轻松添加映射,如果不存在映射,它将默认为当前映射。
这种方法的主要优点是能够修改映射,而无需对代码进行大量更改或要求维护其中的任何逻辑(确保在逻辑 OR 周围加上正确的括号等)。
如果您的意思是您只会遇到这些问题,那么使用其他方法可能是最简单的方法。作为以前处理过类似文件类型的人,我希望您可以快速规范化其他值。
我通过解析包含一些地址的文本文件构造了一个变量。
FileInfo fi = new FileInfo(@"C:\temp\Addresses.txt")
var ZipCodesAndCountryCodes = File.ReadLines(fi.FullName)
.Select(l => new
{
ZipCode = l.Substring(1395, 5),
CountryCode = String.IsNullOrWhiteSpace(l.Substring(1405,30))
? "US"
: l.Substring(1405,30)
});
在此代码中,我将国家/地区的任何空白值替换为 "US"。但是,如果国家/地区是 "United States" 或 "United States of America" 或 "USA",我也想将其标准化为 "US"。我怎样才能在 LINQ 中做到这一点?如果是任何其他国家/地区,则应按原样包括在内。
速度也是一个考虑因素,因为我要解析的文本文件将有 800MB 左右。感谢您的帮助。
更新 1: 当我尝试 Mark 和 Aush 的回答时出现此错误:
System.ObjectDisposedException: Cannot read from a closed TextReader.
at System.IO.__Error.ReaderClosed()
at System.IO.StreamReader.ReadLine()
at System.IO.File.<InternalReadLines>d__0.MoveNext()
at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
at System.Linq.Lookup`2.Create[TSource](IEnumerable`1 source, Func`2 keySelector, Func`2 elementSelector, IEqualityComparer`1 comparer)
at System.Linq.GroupedEnumerable`3.GetEnumerator()
at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
at AnthemMDTS.Program.Main(String[] args) in c:\Projects\CustomerA\CustomerATax\Program.cs:line 100
这里提到的 TextReader 是什么?我没有关闭任何东西,代码中也没有任何循环。
FileInfo fi = new FileInfo(@"C:\temp\Addresses.txt")
var ZipCodesAndCountryCodes = File.ReadLines(fi.FullName).Select(l =>
{
var countrySubstr = l.Substring(1405,30);
return new
{
ZipCode = l.Substring(1395, 5),
CountryCode = string.IsNullOrWhiteSpace(countrySubstr)
|| countrySubstr == "USA"
|| countrySubstr == "United States"
|| countrySubstr == "United States of America"
? "US" : countrySubstr
};
});
您可以在查询表达式中使用 let
子句来存储国家名称 Substring()
的结果。
var ZipCodesAndCountryCodes = from line in File.ReadLines(fi.FullName)
let country = line.Substring(1405,30)
select new
{
ZipCode = line.Substring(1395, 5),
CountryCode = ( string.IsNullOrWhiteSpace(country)
|| country=="United States"
|| country=="United States of America"
|| country=="USA")
? "US"
: country
};
string[] textToSearch = new []{"US","United States","United States of America", "USA"};
FileInfo fi = new FileInfo(@"C:\temp\Addresses.txt")
var ZipCodesAndCountryCodes = File.ReadLines(fi.FullName).Select(l => new
{
ZipCode = l.Substring(1395, 5),
CountryCode = (string.IsNullOrWhiteSpace(l.Substring(1405,30)
|| textToSearch.Contains(l.Substring(1405,30))
? "US"
: l.Substring(1405,30)
});
我可能会使用 GroupJoin
本质上 LEFT OUTER JOIN
具有预定义映射的值。
Dictionary<string, string> mappings = new Dictionary<string, string>()
{
{ "United States", "US" },
{ "United States of America", "US" },
{ "USA", "US" }
};
return ZipCodesAndCountryCodes
.GroupJoin(mappings,
a => a.CountryCode,
b => b.Key,
(a, b) => new {
a.ZipCode,
CountryCode = b.Select(x => x.Value).FirstOrDefault() ?? a.CountryCode
},
StringComparer.CurrentCultureIgnoreCase);
这使您可以轻松添加映射,如果不存在映射,它将默认为当前映射。
这种方法的主要优点是能够修改映射,而无需对代码进行大量更改或要求维护其中的任何逻辑(确保在逻辑 OR 周围加上正确的括号等)。
如果您的意思是您只会遇到这些问题,那么使用其他方法可能是最简单的方法。作为以前处理过类似文件类型的人,我希望您可以快速规范化其他值。