C ++ (VC) Текстовый вывод разбивает строки с 0d 0d 0a вместо 0d 0a — как это исправить?

РЕДАКТИРОВАТЬ: Решение этой проблемы было предоставлено Ульрихом Экхардтом в комментариях ниже. Кроме того: эта проблема имела совершенно другую причину и решение, чем те, которые описаны в возможных дубликатах. Снова, см. Комментарий Ульриха Экхардта для деталей.

С помощью экспертов здесь мне удалось собрать программу, которая записывает содержимое буфера обмена Windows в текстовый файл на указанной кодовой странице. Теперь кажется, что он работает отлично, за исключением того, что разрывы строк в текстовом файле составляют три байта — 0d 0d 0a — вместо 0d 0a — и это вызывает проблемы (дополнительные строки), когда я импортирую текст в текстовый процессор.

Есть ли простой способ заменить 0d 0d 0a на 0d 0a в текстовом потоке, или я должен что-то делать по-другому в моем коде? Я не нашел ничего подобного в другом месте. Вот код:

#include <stdafx.h>
#include <windows.h>
#include <iostream>
#include <fstream>
#include <codecvt> // for wstring_convert
#include <locale>  // for codecvt_byname
using namespace std;

void BailOut(char *msg)
{
fprintf(stderr, "Exiting: %s\n", msg);
exit(1);
}

string ExePath()
{
char buffer[MAX_PATH];
GetModuleFileNameA(NULL, buffer, MAX_PATH);
string::size_type pos = string(buffer).find_last_of("\\/");
return string(buffer).substr(0, pos);
}

// get output code page from command-line argument; use 1252 by default
int main(int argc, char *argv[])
{
string codepage = ".1252";

if (argc > 1) {
string cpnum = argv[1];
codepage = "." + cpnum;
}

// HANDLE clip;
string clip_text = "";

// exit if clipboard not available
if (!OpenClipboard(NULL))
{ BailOut("Can't open clipboard"); }

if (IsClipboardFormatAvailable(CF_TEXT)) {
HGLOBAL hglb = GetClipboardData(CF_TEXT);

if (hglb != NULL) {
LPSTR lptstr = (LPSTR)GlobalLock(hglb);

if (lptstr != NULL) {
// read the contents of lptstr which just a pointer to the string:
clip_text = (char *)hglb;
// release the lock after you're done:
GlobalUnlock(hglb);
}
}
}

CloseClipboard();

// create conversion routines
typedef std::codecvt_byname<wchar_t, char, std::mbstate_t> codecvt;
std::wstring_convert<codecvt> cp1252(new codecvt(".1252"));
std::wstring_convert<codecvt> outpage(new codecvt(codepage));

std::string OutFile = ExePath() + "\\#clip.txt"; // output file name

ofstream OutStream;  // open an output stream
OutStream.open(OutFile, ios::out | ios::trunc);

// make sure file is successfully opened
if (!OutStream) {
cout << "Error opening file " << OutFile << " for writing.\n";
return 1;
}

// convert to DOS/Win codepage number in "outpage"OutStream << outpage.to_bytes(cp1252.from_bytes(clip_text)).c_str();
//OutStream << endl;
OutStream.close(); // close output stream
return 0;
}

0

Решение

Комментарии здесь находятся на правильном пути, но позвольте мне предоставить больше контекста и указать на давнюю проблему.

Существуют различные соглашения об ограничении / разделении строк. Многие производные от Unix системы используют символ перевода строки в конце каждой строки. В ASCII это '\x0A', Другие системы, такие как Windows и многие сетевые протоколы, используют возврат каретки с последующим переводом строки между строками. В ASCII это '\x0D' '\x0A', (Есть и другие схемы, но они гораздо реже.)

Библиотеки ввода / вывода C и C ++ для чтения и записи текста могут скрывать от вас эти соглашения, так что вы можете исправить код одним способом, который делает «правильные вещи» на любой базовой платформе.

Соглашение о программировании заключается в использовании '\n', что почти наверняка эквивалентно переводу строки, если ваша базовая платформа использует ASCII или Unicode (но не если она использует EBCDIC, который не имеет символа перевода строки). При записи в файл библиотека будет перехватывать '\n' и поставьте все, что требуется вашей платформе Например, если вы работаете на компьютере с Linux, он выведет перевод строки (и так как '\n' имеет то же значение, что и перевод строки, это, по сути, запрет). В Windows библиотека будет перехватывать '\n' и вывести возврат каретки и перевод строки. Входная сторона вещей делает обратное.

Когда вы получаете текст из буфера обмена в Windows, вы не знаете, какое соглашение он использует. Поскольку это Windows, вы, вероятно, ожидаете CR + LF, но многие программы, которые могут помещать текст в буфер обмена, могут не работать должным образом в Windows.

В вашем случае кажется, что текст из буфера обмена действительно имеет как возврат каретки, так и перевод строки между строками. Когда вы затем выводите это в текстовом режиме, библиотека ввода / вывода выводит возврат каретки, а затем видит перевод строки (который она считает '\n'), и поэтому он выводит другой возврат каретки, за которым следует перевод строки. Вот почему вы видите удвоение возвратов каретки.

Переключение вывода в двоичный режим говорит библиотеке «не конвертировать» '\n'Итак, это решает вашу непосредственную проблему.

Но по-прежнему существует проблема, заключающаяся в том, что текст буфера обмена иногда может содержать только переводы строк между (или в конце) строками. Если вы выводите это в двоичном режиме, вы не получите возврат каретки, и файл технически не будет в том формате, который требуется вашей платформе. Некоторые программы справятся с этим, а другие, например Notepad, не справятся.

Дополнительная информация.

2

Другие решения


По вопросам рекламы ammmcru@yandex.ru
Adblock
detector