LINQ替换不同的字符串值

时间:2015-03-03 19:52:57

标签: c# linq .net-4.5

我通过解析带有一些地址的文本文件构建了一个变量。

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”替换国家/地区的任何空白值。但是,如果该国是“美国”或“美利坚合众国”或“美国”,我也想将其标准化为“美国”。我怎么能在LINQ中做到这一点?如果是任何其他国家,则应按原样包括在内。

速度也是一个考虑因素,因为我要解析的文本文件将是800MB左右。谢谢你的帮助。

UPDATE1: 当我尝试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?我没有关闭任何东西,代码中也没有任何循环。

4 个答案:

答案 0 :(得分:3)

您可以在查询表达式中使用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
                              };

答案 1 :(得分:1)

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
    };
});

答案 2 :(得分:1)

我可能会使用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之间使用正确的括号等)。

如果你的字面意思是那些是你遇到过的唯一的,那么使用另一种方法可能最容易。而作为之前处理过类似文件的人,我希望还有其他值,你很快就会想要规范化。

答案 3 :(得分:0)

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)
});