коллеги.
Есть БД MySQL с русским текстом.
Есть приложение C# WinForms x86 .net 3.5.
Есть файл .rtf
с вставками вида #template# и русским текстом.
Задача: записать текст из БД в нужные места в файле.
Читаю через File.ReadAllText
, затем склеиваю строки и пишу обратно через File.WriteAllText
в новый файл.
И получаю кракозябры вместо вставленного текста. При этом тот текст, что был, остаётся в порядке.
Пробовал читать в одной кодировке, писать в другой... Один пёс.
Может, кто-то сталкивался с этим .rtf
- какую комбинацию кодировок посоветуете для базы данных, самого файла, File.ReadAllText
и File.WriteAllText
? Или может юзать File.Write/ReadAllBytes
. Или перекодировать на лету вставляемые куски текста?
Заранее спасибо.
Я до сих пор не въехал, какая родная кодировка у .rtf
- 1251 или 1252.
UPD: Код:
string agreementTemplate = File.ReadAllText("PaymentTemplate.rtf", Encoding.GetEncoding(1251));
agreementTemplate = agreementTemplate.Replace("#klientName#", CurrentCredit.Client);
agreementTemplate = agreementTemplate.Replace("#klientAdr#", CurrentCredit.ClientAdr);
File.WriteAllText("Сведения о платежах для договора №" + CurrentCredit.Number + ".doc", agreementTemplate, Encoding.GetEncoding(1251));
Результат: Андрей Семёнов óë. Ëåíèíà, 24
Добавил новый файл для примера. При загрузке: "{\rtf1\ansi\ansicpg1251\deff0{\fonttbl{\f0\fnil\fcharset204 Calibri;}{\f1\fnil\fcharset0 Calibri;}}\r\n\viewkind4\uc1\pard\sa200\sl276\slmult1\lang1049\f0\fs22\'d0\'f3\'f1\'f1\'ea\'e8\'e9 \'f2\'e5\'ea\'f1\'f2\lang1033\f1\par\r\n\lang1049\b\f0\'d0\'f3\'f1\'f1\'ea\'e8\'e9 \'f2\'e5\'ea\'f1\'f2\lang1033\f1\par\r\n\lang1049\ul\b0\f0\'d0\'f3\'f1\'f1\'ea\'e8\'e9 \'f2\'e5\'ea\'f1\'f2\lang1033\f1\par\r\n\lang1049\b\f0\'d0\'f3\'f1\'f1\'ea\'e8\'e9 \'f2\'e5\'ea\'f1\'f2\lang1033\f1\par\r\n\lang1049\ulnone\b0\f0\'d0\'f3\'f1\'f1\'ea\'e8\'e9 \'f2\'e5\'ea\'f1\'f2\lang1033\f1\par\r\n\lang1049\f0\'d0\'f3\'f1\'f1\'ea\'e8\'e9 \'f2\'e5\'ea\'f1\'f2: \lang1033\f1 #replace#\par\r\n\lang1049\f0\'d0\'f3\'f1\'f1\'ea\'e8\'e9 \'f2\'e5\'ea\'f1\'f2\lang1033\f1\par\r\n\lang1049\f0\'d0\'f3\'f1\'f1\'ea\'e8\'e9 \'f2\'e5\'ea\'f1\'f2\lang1033\f1\par\r\n\par\r\n\par\r\n}\r\n"
После замены replace на русский текст
"{\rtf1\ansi\ansicpg1251\deff0{\fonttbl{\f0\fnil\fcharset204 Calibri;}{\f1\fnil\fcharset0 Calibri;}}\r\n\viewkind4\uc1\pard\sa200\sl276\slmult1\lang1049\f0\fs22\'d0\'f3\'f1\'f1\'ea\'e8\'e9 \'f2\'e5\'ea\'f1\'f2\lang1033\f1\par\r\n\lang1049\b\f0\'d0\'f3\'f1\'f1\'ea\'e8\'e9 \'f2\'e5\'ea\'f1\'f2\lang1033\f1\par\r\n\lang1049\ul\b0\f0\'d0\'f3\'f1\'f1\'ea\'e8\'e9 \'f2\'e5\'ea\'f1\'f2\lang1033\f1\par\r\n\lang1049\b\f0\'d0\'f3\'f1\'f1\'ea\'e8\'e9 \'f2\'e5\'ea\'f1\'f2\lang1033\f1\par\r\n\lang1049\ulnone\b0\f0\'d0\'f3\'f1\'f1\'ea\'e8\'e9 \'f2\'e5\'ea\'f1\'f2\lang1033\f1\par\r\n\lang1049\f0\'d0\'f3\'f1\'f1\'ea\'e8\'e9 \'f2\'e5\'ea\'f1\'f2: \lang1033\f1\'c0\'ed\'e4\'f0\'e5\'e9 \'d1\'e5\'ec\'b8\'ed\'ee\'e2\par\r\n\lang1049\f0\'d0\'f3\'f1\'f1\'ea\'e8\'e9 \'f2\'e5\'ea\'f1\'f2\lang1033\f1\par\r\n\lang1049\f0\'d0\'f3\'f1\'f1\'ea\'e8\'e9 \'f2\'e5\'ea\'f1\'f2\lang1033\f1\par\r\n\par\r\n\par\r\n}\r\n"
Содержимое файла
Русский текст Русский текст (жирным) Русский текст (подчёркнутым) Русский текст (жирным подч) Русский текст Русский текст: #replace# Русский текст Русский текст
Обновление: решение проблемы, как обычно, с помощью костылей. Вместо шаблона вида "#replace#" делаем шаблон КИРИЛЛИЦЕЙ вида "ИмяКлиента".
То есть текст в шаблоне: "клиент, в лице ИмяКлиента, обязывается..."
Затем, с помощью функции, предложенной nick_n_a, делаем такую кракозябру:
templateStr = loadfile...
templateStr = templateStr.Replace(ToRtf("ИмяКлиента"), ToRtf(CurrentCredit.Name));
где CurrentCredit.Name - русский текст из БД На кодировку ложим болт ибо теперь неважно.
В общем, оно работает. Но... сами понимаете. Кто придумает что-то лучше - милости просим)
ЗЫ: правда, на основных файлах ещё не проверял, если что - вернусь)
Для вставки текста RTF в шаблон я использовал такое приведение
public static string toRTF(string value)
{ /*Конвертирует текст, в текст пригодный для RTF документа */
// FF
string syms = @"ЎўЈЈ¤Ґ¦§Ё©Є«¬®Ї°±Ііґµ¶•ё№є»јЅѕїАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюя";
string rep_1 = @"0123456789abcdef";
int j = 0;
int k = 0;
while (j < value.Length)
{
if (syms.IndexOf(value[j]) >= 0)
{
k = syms.IndexOf(value[j]);
value = value.Replace(value[j].ToString(), "\\'" + rep_1[(k / 16) + 10].ToString() + rep_1[k & 15].ToString());
};
j++;
};
value = value.Replace("\\n", "\\par;");
return value;
}
Да.. пожалуй хранить и копировать таблицу сложно... вариант 2 - без таблицы
public static string toRTF(string value)
{ /*Конвертирует текст, в текст пригодный для RTF документа */
byte[] t = new byte[1];
int j = 0;
while (j < value.Length)
{
if (value[j] >= '\x7F')
{
System.Text.Encoding.GetEncoding(1251).GetBytes(value,j,1,t,0);
value = value.Replace(value[j].ToString(), "\\'" + t[0].ToString('x'));
};
j++;
};
value = value.Replace("\\n", "\\par;");
return value;
}
Т.е. буква я маленькая имеет код \'FF
. Плюс... шаблон должен содержать метку 1251, т.е. в файле с поддержкой 1251 заголовок должен быть такой
{\rtf1\adeflang1025\ansi\ansicpg1251\
Еще я заменяю возврат каретки на \par;
потому что текст так переносится в rtf.
Текст можно вообще не преобразовывать, оставить как есть и лишь перенести в кодировку 1251, если есть уверенность, что ваш файл будут открывать исключительно в среде windows. Некоторые "неродные" редакторы не понимают файлы без указанного перевода.
P.S. RTF не самый простой формат, не могу рассказать подробно о его деталях. Приведенный код использую в одном из проэктов. Преобразование в heх можно реализовать лучше.. но так уже получилось - не само оптимально. В вики внизу есть ссылка на спецификацию http://ru.wikipedia.org/wiki/Rich_Text_Format, если есть сложности - думаю спецификацикация даст ответ на ваши вопросы.
Если вас не интересует поддержка старого ПО, можно закодировать в Unicode, тогда проблемы кодировки не будет. Для этого пропустите строку через такой метод:
static string RtfEncode(string input)
{
StringBuilder sb = new StringBuilder(input.Length * 4);
foreach (var c in input)
{
if (c > 127) //заменяем не-ASCII символы на их Unicode представление
{
string escape = "\\u" + ((Int16)c).ToString() + "?";
sb.Append(escape);
}
else //ASCII добавляем без изменений
{
sb.Append(c);
}
}
return sb.ToString();
}
Тогда замену можно произвести как-то так:
string template = "#template#";
string word = "Иванов И.А.";
string contents = File.ReadAllText(input_file);
word = RtfEncode(word);
contents = contents.Replace(template, word);
File.WriteAllText(output_file, contents);
О кодировке не нужно заботиться, так как после RtfEncode задействованы только ASCII символы. При таком способе ничего не должно нарушиться, при условии что маркер замены в шаблоне никак не пересекает границы управляющих конструкций RTF. (Отредактируйте шаблон в блокноте, и убедитесь, что строка замены представлена именно так, как вы ожидаете.)
Как всё заработало в итоге.
//виртуальный буфер (глобальная переменная)
private RichTextBox _richTextBox = new RichTextBox();
//название файла для сохранения
string target = "Договор №" + CurrentCredit.Number + ".doc";
//грузим шаблон в RichTextBox - контрол сам порешает за все кодировки
_richTextBox.LoadFile(Storage.AgreementTemplateFile, RichTextBoxStreamType.RichText);
//магия
Replace("#nomer#", CurrentCredit.Number.ToString());
//при сохранении о кодировке опять-таки позаботится RichTextBox
_richTextBox.SaveFile(target);
//главное - функция Replace:
private void Replace(string from, string to)
{
int start = _richTextBox.Find(from, 0, RichTextBoxFinds.None);
_richTextBox.Select(start, from.Length);
_richTextBox.SelectedText = to;
}
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
Какие существуют виды рекламных бордов и как выбрать подходящий?
Написал простенький код, который при вводе числа должен выдать на 10 большекомпилирую, нажимая F5
Помогите сделать так чтобы при нажатии на кнопку удалялась выделенная строчка в DataGridView из базы данных
как можно перенести на 2 лист, где: Нижняя челюсть - Левая сторона от 44, хочу перенести на 2 листНо как можно сделать?