Замена символов Non-Ascii некоторыми алфавитами для поддержания формата файла таким же образом

Вот мой код:

byte[] bytes = File.ReadAllBytes(@"D:\project\wb_header.txt");
byte[] outp = bytes.Where(c => c >= 32 && c < 127).ToArray();
File.WriteAllBytes(@"D:\project\outputfile.txt", outp);

Здесь я подсчитываю все символы Non- Ascii в файле wb_header.txt и после удаления символов Non- ascii, которые создает выходной файл. Но проблема в том, что я не хочу удалять символы, и я хочу заменить его некоторыми алфавитами или символами ASCII, чтобы поддерживать тот же формат файла, что и файл wb_header.txt. Как это сделать? Пожалуйста, укажите код здесь

1 ответ

Ваш код работает только в том случае, если ваш исходный файл ASCII, в этом случае, если вы просто хотите удалить непечатаемые (такие старые определения, я знаю) символы:

byte[] output = bytes .Select(c => (c >= 32 && c <= 127) ? c : (byte)63).ToArray();

Это удалило все непечатаемые символы, заменив их на ? (знак вопроса, код ASCII 63).

Теперь давайте посмотрим, почему ваш исходный код не работает для файлов без ASCII. Текст всегда кодирует (ASCII, UTF-8, UTF-16 и многие другие). Первые 127 значений в большинстве кодировок одинаковы, поэтому ваш код может работать, но есть символы, которые должны быть закодированы, потребуется больше одного байта. Например, это итальянское предложение: È sù будет закодировано в UTF-8 следующим образом:

Bytes Characters
195 136 <kbd>È</kbd>
32 <kbd> </kbd>
115 <kbd>s</kbd>
195 185 <kbd>ù</kbd>

Как видите, некоторым персонажам требуется более одного байта. Значения, разумеется, различны для разных кодировок. Кроме того, некоторые текстовые файлы имеют маркер спецификации, чтобы явно их кодировать (и его следует просто игнорировать). Существуют некоторые методы преобразования, например, è в e (некоторые очень хорошие статьи здесь на SO), но, к сожалению, вы никогда не сможете обрабатывать текст без ASCII в виде байтов (я даже не упоминаю языки на дальнем востоке). Хорошим приближением может быть первое чтение файла в виде текста (если вы не знаете, что его инфраструктура кодирования может проверять вас, если файл начинается с спецификации, это серьезная проблема, поскольку, если у вас нет достаточных знаний о содержимом файла, вы не можете предположим, см. это тоже):

string content = File.ReadAllText("file.txt");

Теперь давайте получим его представление в ASCII (символы без ASCII будут автоматически заменены на ?):

byte[] output = Encoding.ASCII.GetBytes(content);

Этот массив байтов будет включать непечатаемые символы (вне диапазона [32... 127]), тогда вам все равно может понадобиться применить тот же фильтр:

byte[] output = Encoding.ASCII.GetBytes(content) .Select(c => (c >= 32 && c <= 127) ? c : (byte)63).ToArray();

Заключительные примечания: этот код неэффективен вообще. Мы читаем весь файл в памяти, преобразуем его в массив байтов (в памяти), затем создаем копию (снова в памяти), чтобы, наконец, записать ее обратно... для файлов размером более нескольких килобайт вы должны читать символы непосредственно из файла ( один за другим) с надлежащим кодированием. Ах... не забывайте суррогаты и модификаторы UNICODE...

licensed under cc by-sa 3.0 with attribution.