2015-03-03 3 views
0

Я построил переменную, проанализировав текстовый файл с помощью некоторых адресов.LINQ Заменить различные строковые значения

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

В этом коде я заменяю пустое значение для страны на «США». Однако я также хочу нормализовать его до «США», если страна «Соединенные Штаты» или «Соединенные Штаты Америки» или «США». Как я могу это сделать в LINQ? Если это какая-либо другая страна, она должна быть включена как есть.

Скорость также является соображением, так как текстовые файлы, которые будут обрабатываться, будут составлять 800 МБ. Спасибо за любую помощь.

Update1: Я получаю эту ошибку, когда я попытался ответить Марка и 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 здесь идет речь? Я ничего не закрываю, и в коде нет циклов.

+0

вам нужно использовать LINQ? с большим файлом, вы должны использовать filereader для анализа данных, а затем вставить его в конструкцию. –

+0

LINQ используется в основном из-за некоторой группировки и агрегации, которая должна быть выполнена, а также потому, что нет базы данных. – FMFF

ответ

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

Получение 'System.ObjectDisposedException: невозможно прочитать из закрытого TextReader.' – FMFF

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 
           }; 
+0

Марк, я попробовал ваш ответ; получение 'System.ObjectDisposedException: невозможно прочитать из закрытого TextReader.' в этой строке. Любая идея почему? – FMFF

+1

Перечислитель, возвращаемый 'File.ReadLines()', использует 'TextReader', который, кажется, закрыт вызовом оператора GroupBy(). Вместо этого вы можете использовать File.ReadAllLines(), чтобы сначала выгрузить все это в массив. –

+0

С ReadAllLines() Я получаю OutOfMemory Exception когда; текстовый файл настолько большой (~ 800 МБ - 1,2 ГБ). Он работал в тестовых машинах, хотя и с образцами файлов. – FMFF

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) 
}); 
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 и т. Д.).

Если вы буквально означали, что это единственные, с которыми вы когда-либо столкнетесь, возможно, проще всего использовать другой подход. И как кто-то, кто раньше сталкивался с подобными типами файлов, я ожидал бы, что будут другие значения, которые вы хотите нормализовать довольно быстро.

Смежные вопросы