«É» неправильно преобразуется в два байта - PullRequest
1 голос
/ 21 апреля 2010

В дополнение к этот вопрос У меня есть дополнительная проблема.

Я нашел трек с "É" в названии.

Мой код:

var playList = new StreamWriter(playlist, false, Encoding.UTF8);

-

private static void WriteUTF8(StreamWriter playList, string output)
{
    byte[] byteArray = Encoding.UTF8.GetBytes(output);
    foreach (byte b in byteArray)
    {
        playList.Write(Convert.ToChar(b));
    }
}

преобразует это в следующие байты:

195
137

, который выводится как Ã, за которым следует квадрат (символ, который не может быть напечатан в текущем шрифте ).

Я экспортировал тот же файл в список воспроизведения в Media Monkey, в котором записано «É» как «Ã ‰» - что я считаю правильным (как указал KennyTM).

Мой вопрос: как мне получить вывод символа "‰"? Нужно ли выбирать другой шрифт, и если да, то какой?

UPDATE

Люди, кажется, упускают суть.

Я могу получить "É", записанную в файл, используя

playList.WriteLine("É");

это не проблема.

Проблема в том, что Media Monkey требует, чтобы файл был в следующем формате:

#EXTINFUTF8:140,Yann Tiersen - Comptine D'Un Autre Été: L'Après Midi
#EXTINF:140,Yann Tiersen - Comptine D'Un Autre Été: L'Après Midi
#UTF8:04-Comptine D'Un Autre Été- L'Après Midi.mp3
04-Comptine D'Un Autre Été- L'Après Midi.mp3

Где все "старшие слова" (из-за отсутствия лучшего термина) записаны в виде пары символов.

ОБНОВЛЕНИЕ 2

Мне нужно заменить c9 на c3 89.

Я собирался поставить то, что на самом деле получаю, но при выполнении тестов для этого мне удалось получить тестовую программу для вывода текста в правильном формате «как есть». Поэтому мне нужно провести дополнительное расследование.

Ответы [ 5 ]

3 голосов
/ 21 апреля 2010

Использование Convert.ToChar почти наверняка плохая идея. Вы в основном кодируете вещи дважды.

Вы должны либо выполнить преобразование самостоятельно, а затем записать напрямую в поток, или , вы должны позволить StreamWriter выполнить преобразование. Почему вы вообще используете StreamWriter, если пытаетесь выполнить преобразования самостоятельно?

Вы пытаетесь записать в двоичный файл или в простой текстовый файл? Если это простой текстовый файл, просто используйте StreamWriter, и пусть это сделает преобразование. Если это двоичный файл, используйте Stream вместо StreamWriter и выполняйте кодирование текста непосредственно там, где вам нужно, записывая байты прямо в поток.

РЕДАКТИРОВАТЬ: Вот что происходит с вашим исходным кодом:

Encoding.UTF8.GetBytes(text) => byte[] { 0xc3, 0x89 };

Convert.ToChar(0xc3) => char U+00C3
StreamWriter writes U+00C3 as byte[] { 0xc3, 0x83 };

Convert.ToChar(0x89) => char U+0089
StreamWriter writes U+00C3 as byte[] { 0xc2, 0x89 };

Так вот почему вы записываете в файл c3 83 c2 89.

2 голосов
/ 21 апреля 2010

Более фундаментальная проблема заключается в названии метода:

 private static void WriteUTF8(...)

.M3U файлы не являются UTF-8. Это латиница-1 (или Windows-1252).

Вместо Encoding.UTF8 вы должны использовать Encoding.GetEncoding(1252). Тогда вы можете просто написать прямо в поток, вам не понадобится эта странность преобразования.

Обновление:

Я только что попробовал следующий код C #, и полученный .M3U прекрасно открывается как в Winamp, так и в WMP:

static void Main(string[] args)
{
    string fileName = @"C:\Temp\Test.m3u";
    using (StreamWriter writer = new StreamWriter(fileName, false,
        Encoding.GetEncoding(1252)))
    {
        writer.WriteLine("#EXTM3U");
        writer.WriteLine("#EXTINF:140,Yann Tiersen " +
            "- Comptine D'Un Autre Été: L'Après Midi");
        writer.WriteLine("04-Comptine D'Un Autre Été- L'Après Midi.mp3");
    }
}

Итак, как я уже сказал - просто используйте правильную кодировку для начала. Вам не нужны все эти дополнительные #EXTINFUTF8 и #UTF8 строки, если только это не является каким-то странным требованием для Media Monkey (это определенно не является частью базовой спецификации M3U).

2 голосов
/ 21 апреля 2010

StreamWriter уже преобразует символы, которые вы отправляете в UTF-8 - вот и вся его цель. Выбросить WriteUTF8 прочь; он сломан и бесполезен.

(WriteUTF8 принимает символы, преобразует их в байты UTF-8, преобразует каждый отдельный байт в символ, которому он соответствует в текущей кодовой странице, затем кодирует каждый из этих символов в UTF- 8. Таким образом, в лучшем случае у вас есть строка в кодировке с двойным UTF-8, в худшем - вы полностью потеряли байты, которые не были отображены в репертуаре системных кодовых страниц, особенно плохо для кодовых страниц DBCS.)

Проблема с Media Monkey может заключаться в том, что она вообще не поддерживает имена файлов UTF-8 или Unicode. Попробуйте попросить его воспроизвести (и экспортировать список воспроизведения) файлы с символами, которые не помещаются в вашу системную кодовую страницу, например, переименовав файл в αβγ.mp3.

Edit:

#EXTINFUTF8:140,Yann Tiersen - Comptine D'Un Autre Été: L'Après Midi
#EXTINF:140,Yann Tiersen - Comptine D'Un Autre Été: L'Après Midi
#UTF8:04-Comptine D'Un Autre Été- L'Après Midi.mp3
04-Comptine D'Un Autre Été- L'Après Midi.mp3

Хорошо, у вас есть смесь кодировок в одном и том же файле: неудивительно, что текстовым редакторам будет трудно открыть его. Некомментированные и #EXTINF строки находятся в системной кодовой странице по умолчанию и присутствуют для поддержки медиаплееров, которые не могут прочитать имена файлов Unicode. Любые символы имени файла, отсутствующие в системной кодовой странице (например, греческий, как указано выше, при установке в Windows), будут искажены и не будут воспроизведены для всего, что не знает о строках #UTF8#EXTINFUTF8 для описания) .

Итак, если это ваш целевой формат, вам нужно взять две кодировки и использовать каждую по очереди, что-то вроде:

private static void writePlaylistEntry(Stream playlist, string filename, int length) {
    Encoding utf8= new UTF8Encoding(false);
    Encoding ansi= Encoding.Default;
    playlist.Write(utf8.GetBytes("#EXTINFUTF8:"+length+","+filename+"\n"));
    playlist.Write(ansi.GetBytes("#EXTINF:"+length+","+filename+"\n"));
    playlist.Write(utf8.GetBytes("#UTF8:"+filename+"\n"));
    playlist.Write(ansi.GetBytes(filename+"\n"));
}
2 голосов
/ 21 апреля 2010

Я не делаю C #, но симптомы говорят мне, что вы действительно пишете это как UTF-8, но что вывод / консоль / приложение / все, с чем вы просматриваете написанное вывод не использует UTF-8, но ISO-8859-1 для их отображения и что MediaMonkey использует CP1252 для их отображения.

Если вы просматриваете их в консоли IDE, вам необходимо настроить IDE для использования UTF-8 в качестве консоли и кодировки текстовых файлов.

Обновление вы, очевидно, хотите записать UTF-8 данные как CP-1252. Теперь вопрос / проблема понятнее. Опять же, я не делаю C #, но эквивалент Java будет:

Writer writer = new OutputStreamWriter(new FileOutputStream("file.ext"), "CP-1252");
writer.write(someUTF8String); // Will be written as CP-1252. "É" would become "É"

Надеюсь, это даст некоторые идеи.

0 голосов
/ 21 апреля 2010

Хорошо, прежде всего, спасибо всем за помощь и терпение.

У меня наконец-то все работает правильно. Я реализовал версию решения Бобинса, поэтому он получает одобрение (за всех остальных). Вот мой код:

var playList = new StreamWriter(playlist, false, Encoding.Default);
playList.WriteLine("#EXTM3U");

foreach (string track in tracks)
{
    // Read ID3 tags from file
    var info = new FileProperties(track);

    // Write extended info (#EXTINF:<time>,<artist> - <title>
    if (Encoding.UTF8.GetBytes(info.Artist).Length != info.Artist.Length ||
        Encoding.UTF8.GetBytes(info.Title).Length != info.Title.Length)
    {
        playList.Close();
        playList = new StreamWriter(playlist, true, Encoding.UTF8);

        playList.WriteLine(string.Format("#EXTINFUTF8:{0},{1} - {2}",
                           info.Duration, info.Artist, info.Title));

        playList.Close();
        playList = new StreamWriter(playlist, true, Encoding.Default);
    }

    playList.WriteLine(string.Format("#EXTINF:{0},{1} - {2}",
                       info.Duration, info.Artist, info.Title));

    // Write the name of the file (removing the drive letter)
    string file = Path.GetFileName(track);
    if (Encoding.UTF8.GetBytes(file).Length != file.Length)
    {
        playList.Close();
        playList = new StreamWriter(playlist, true, Encoding.UTF8);

        playList.WriteLine(string.Format("#UTF8:{0}", file));

        playList.Close();
        playList = new StreamWriter(playlist, true, Encoding.Default);
    }

    playList.WriteLine(file);
}

playList.Close();

Как вы видите, я предполагаю, что мне не нужно писать UTF8, но когда я это сделаю, я закрываю поток и открываю его с кодировкой UTF8. Затем, после написания ошибочной строки, закройте и снова откройте ее с кодировкой по умолчанию.

Теперь я не знаю, почему мой предыдущий код дал противоречивые результаты. Учитывая то, что все (в частности, Джон) сказали, что он должен был постоянно терпеть неудачу или, возможно, работать постоянно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...