Как читать и писать умные кавычки (и другие глупые символы) в С#

Я пишу программу, которая считывает весь текст в файле в строку, перебирает эту строку, просматривая символы, а затем добавляет символы обратно в другую строку с помощью Stringbuilder. Проблема, с которой я сталкиваюсь, заключается в том, что когда она записывается обратно, специальные символы, такие как и , вместо этого выглядят как символы �. Мне не нужно делать преобразование, я просто хочу, чтобы оно было записано так, как я его прочитал:

    StringBuilder sb = new StringBuilder();
    string text = File.ReadAllText(filePath);
    for (int i = 0; i < text.Length; ++i) {
        if (text[i] != '{') {  // looking for opening curly brace
            sb.Append(text[i]);
            continue;
        }
        // Do stuff
    }
    File.WriteAllText(destinationFile, sb.ToString());

Пробовал использовать разные кодировки (UTF-8, UTF-16, ASCII), но потом получилось еще хуже; Я начал получать символы вопросительного знака и китайские иероглифы (да, это немного упрощенный подход, но я просто экспериментировал). Я прочитал эту статью: http://www.joelonsoftware.com/articles/Unicode.html ... но на самом деле это не объясняло, почему я видел то, что видел, если только в C# читатель не начинает обрезать биты, когда сталкивается с такими странными символами. Заранее благодарю за любую помощь!


person BrDaHa    schedule 30.11.2012    source источник
comment
Если вы отлаживаете это и перешагиваете строку File.ReadAllText, имеет ли переменная text правильные данные или она неверная?   -  person taylorjonl    schedule 30.11.2012
comment
Я разместил некоторые идеи в качестве потенциального ответа. Пожалуйста, посмотрите и дайте мне знать, что вы найдете ...   -  person Miltos Kokkonidis    schedule 30.11.2012
comment
@taylorjonl Это шатко, все символы, отличные от utf-8, имеют на своем месте символ �   -  person BrDaHa    schedule 01.12.2012


Ответы (2)


TL;DR, это определенно не UTF-8, и вы даже не используете UTF-8 для чтения результирующего файла. Читать как Windows1252, писать как Windows1252 (Если вы собираетесь использовать тот же метод просмотра для просмотра результирующего файла)


Ну, давайте сначала просто скажем, что файл, созданный обычным пользователем, не может быть в UTF-8. Не все программы в Windows даже поддерживают его (excel, блокнот...), не говоря уже о том, что он является кодировкой по умолчанию (даже большинство инструментов developer не используют по умолчанию utf-8, что сводит меня с ума). Поскольку многие разработчики не понимают, что такая вещь, как кодировка, вообще существует, то каковы шансы обычных пользователей сохранить свои файлы во враждебной среде utf-8?

Вот тут-то и начинаются ваши проблемы. Согласно документации, используемая вами перегрузка File.ReadAllText(filePath); может обнаруживать только UTF-8 или UTF-32. .

Действительно, простое чтение файла, нормально закодированного в Windows-1252, который содержит "a”a", приводит к строке "a�a", где — это символ замены юникода (прочитайте раздел википедии, он точно описывает ситуацию, в которой вы находитесь!) используется для замены недопустимых байтов. Когда символ замены снова будет закодирован как UTF-8 и интерпретирован как Windows-1252, вы увидите �, потому что байты для в UTF-8 равны 0xEF, 0xBF, 0xBD, которые являются байтами для � в Windows-1252.

Так что читайте это как Windows-1252, и вы на полпути:

Encoding windows1252 = Encoding.GetEncoding("Windows-1252");
String result = File.ReadAllText(@"C:\myfile.txt", windows1252);
Console.WriteLine(result); //Correctly prints "a”a" now

Поскольку вы видели �, инструмент, с помощью которого вы просматриваете только что созданный файл, также использует Windows-1252. Поэтому, если цель состоит в том, чтобы файл отображал правильные символы в этом инструменте, вы должны закодировать вывод как Windows-1252:

Encoding windows1252 = Encoding.GetEncoding("Windows-1252");
File.WriteAllText(@"C:\myFile", sb.toString(), windows1252);
person Esailija    schedule 30.11.2012
comment
Вау, спасибо, это был действительно исчерпывающий ответ! И спасибо, что показали мне эти статьи! Извините, если вопрос был немного подробным, просто не хотел показаться, что я не проводил никаких исследований. Я проголосую за это, когда у меня будет достаточно представителей, чтобы сделать это. - person BrDaHa; 01.12.2012
comment
вроде капля в море, но эй! +1 @Esailija - person BrDaHa; 01.12.2012
comment
@ User1234567890 нет, tl;dr предназначен для обобщения моего ответа: P - person Esailija; 01.12.2012
comment
Пять лет спустя, и это все еще лучший ответ на этот вопрос, и у него всего шесть голосов :( - person Whelkaholism; 22.05.2017

Скорее всего, текст будет UTF8.

File.ReadAllText(filePath, Encoding.UTF8)

в сочетании с

File.WriteAllText(destinationFile, sb.ToString(), Encoding.UTF8)

должен охватывать работу с символами Unicode. Если вы сделаете одно или другое, вы получите вывод мусора, либо оба, либо ничего.

person Steve Py    schedule 30.11.2012