У меня есть текстовый файл, полный записей, где каждое поле в каждой записи имеет фиксированную ширину. Моим первым подходом было бы проанализировать каждую запись, просто используя string.Substring (). Есть ли способ лучше?
Например, формат можно описать как:
<Field1(8)><Field2(16)><Field3(12)>
И пример файла с двумя записями может выглядеть так:
SomeData0000000000123456SomeMoreData
Data2 0000000000555555MoreData
Я просто хочу убедиться, что не упускаю из виду более элегантный способ, чем Substring ().
Обновлять: Я в конечном итоге выбрал регулярное выражение, подобное предложению Killersponge:
private readonly Regex reLot = new Regex(REGEX_LOT, RegexOptions.Compiled);
const string REGEX_LOT = "^(?<Field1>.{6})" +
"(?<Field2>.{16})" +
"(?<Field3>.{12})";
Затем я использую следующее для доступа к полям:
Match match = reLot.Match(record);
string field1 = match.Groups["Field1"].Value;





Нет, подстрока в порядке. Вот для чего это нужно.
Подстрока мне нравится. Единственный недостаток, о котором я могу сразу подумать, - это то, что это означает копирование данных каждый раз, но я бы не стал беспокоиться об этом, пока вы не докажете, что это узкое место. Подстрока простая :)
Вы мог используете регулярное выражение для сопоставления всей записи за раз и захвата полей, но я думаю, что это было бы излишним.
Да, я пытался придумать способ использования регулярного выражения, но думаю, что это неправильный инструмент для работы и, как вы сказали, излишний.
регулярное выражение? ^ (. {8}) (. {16}) (. *) $ Для приведенного выше определения полей, предполагая, что последнее поле может или не может быть дополнено пробелами.
Возможно, вам придется следить за тем, если конец строк не заполнен пробелами для заполнения поля, ваша подстрока не будет работать, если немного поиграться, чтобы определить, сколько еще строки нужно прочитать. Это, конечно, относится только к последнему полю :)
Используйте FileHelpers.
Пример:
[FixedLengthRecord()]
public class MyData
{
[FieldFixedLength(8)]
public string someData;
[FieldFixedLength(16)]
public int SomeNumber;
[FieldFixedLength(12)]
[FieldTrim(TrimMode.Right)]
public string someMoreData;
}
Тогда это так просто:
var engine = new FileHelperEngine<MyData>();
// To Read Use:
var res = engine.ReadFile("FileIn.txt");
// To Write Use:
engine.WriteFile("FileOut.txt", res);
Для этого нужны какие-то дженерики, может, мне стоит взглянуть и сделать это: P
-1 для решения, зависящего от внешней библиотеки, неоптимально.
К сожалению, из коробки CLR предоставляет для этого только Substring.
Кто-то в CodeProject создал собственный парсер, используя атрибуты для определения полей., вы могли бы посмотреть на это.
Вы можете настроить источник данных ODBC для файла фиксированного формата, а затем обращаться к нему как к любой другой таблице базы данных. Это имеет дополнительное преимущество, заключающееся в том, что конкретные знания о формате файла не включаются в ваш код для того рокового дня, когда кто-то решает вставить дополнительное поле посередине.
Зачем изобретать велосипед? Используйте класс .NET TextFieldParser согласно этому руководству для Visual Basic: Как читать из текстовых файлов фиксированной ширины.
Можно использовать следующую библиотеку: https://github.com/borisdj/FixedWidthParserWriter