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 周围加上正确的括号等)。

如果您的意思是您只会遇到这些问题,那么使用其他方法可能是最简单的方法。作为以前处理过类似文件类型的人,我希望您可以快速规范化其他值。