Изменить кодировку командной строки windows

Dd и разбивка образов на файлы

В цифровой криминалистике стало обычной практикой разделять выходные данные образов на несколько файлов. Это делается по ряду причин: либо для архивирования, либо для использования в другой программе. Сначала мы обсудим самостоятельное использование split, а затем вместе с dd для разделения «на лету».

Связанная статья: Инструкция по использованию split

Например, у нас есть образ размером 80 ГБ, и теперь мы хотим разделить его на части по 4 ГБ, чтобы их можно было записать на другой носитель. Или, если вы хотите хранить файлы в файловой системе с ограничениями на размер файла и вам нужен определённый размер, вы можете разделить образ на более мелкие разделы.


Для этого мы используем команду split.

Команда split обычно работает со строками ввода (то есть из текстового файла). Но если мы используем параметр -b, мы заставляем split рассматривать файл как двоичный ввод, а строки игнорируются. Мы можем указать размер файлов, которые мы хотим, вместе с префиксом, который мы хотим для выходных файлов. split также может использовать параметр -d, чтобы дать нам числовую нумерацию (*.01 , *.02 , *.03 и т. д.) для выходных файлов, а не алфавитную, которая применяется по умолчанию (*.aa , *.ab , *.ac, и т.д.). Параметр -a указывает длину суффикса. Команда выглядит так:

split -d -a ЧИСЛО -b РАЗМЕРG ФАЙЛ_ДЛЯ_РАЗБИВКИ ПРЕФИКС_ВЫХОДНЫХ_ФАЙЛОВ

где ЧИСЛО — длина расширения (или суффикса), которое мы будем использовать, а РАЗМЕР — это размер результирующих файлов с модификатором единиц (K, M, G и т. д.). Наш образ /dev/sdd мы можем разделить его на файлы размером 4 ГБ с помощью следующей команды (размер последнего файла будет соответствовать оставшейся части тома, если он не является точно кратным выбранному вами размеру):

split -d -a 3 -b 4G case1.disk1.raw case1.disk1.split.

Это приведёт к созданию группы файлов (размером 4 ГБ), каждый из которых будет назван префиксом case1.split1, как указано в команде, за которым следует .000, .001, .002 и т. д. Параметр -a с 3 указывает, что мы хотим, чтобы расширение было не менее 3 цифр.

Без -a 3 наши файлы будут называться .000 , .001 , .002 и т. д. Использование трёх цифр обеспечивает согласованность с другими инструментами — некоторые наборы программного обеспечения для судебной экспертизы не распознают разделённые изображения, имена которых имеют расширение, отличное от трёх символов.

Процесс можно повернуть вспять. Если мы хотим повторно собрать образ из разделённых частей, мы можем использовать команду cat и перенаправить вывод в новый файл. Помните, что cat просто выводит указанные файлы на стандартный вывод. Если вы перенаправите этот вывод, файлы будут собраны в один.

cat case1.disk1.split* > case1.disk1.new.raw

В приведённой выше команде мы повторно собрали разделённые части в новый файл образа размером 80 ГБ. Исходные разделённые файлы не удаляются, поэтому приведённая выше команда существенно удвоит ваши требования к свободному месту на диске, если вы выполняете запись в одно и то же смонтированное устройство/каталог.

Эту же команду cat можно использовать для проверки хеша результирующих разделов образа путём передачи по конвейеру всех частей образа с помощью символа | (труба) в нашу команду хеширования:

cat case1.disk1.split* | sha1sum
ddddda4252d1adeffa267636b1ae0fbf40c9d3b3 -

Ещё раз видим, что хеш остаётся неизменным. Знак – в конце вывода означает, что мы взяли ввод со стандартного ввода, а не из файла или устройства. В приведённой выше команде sha1sum получает входные данные напрямую от команды cat через трубу.

Другой способ создания многосегментных образов — разделение образа по мере его создания (непосредственно с помощью команды dd). По сути, это разделение «на лету», о котором мы упоминали ранее. Мы делаем это, передавая вывод команды dd прямо в split, опуская часть of= команды dd. Предполагая, что наш целевой диск — /dev/sdd, мы должны использовать команду:

dd if=/dev/sdd | split -d -a 3 -b 4G - case1.disk1.split.
156250000 0 records in
156250000 0 records out
80000000000 bytes (80 GB, 75 GiB) copied, 1146.87 s, 69.8 MB/s

Здесь вместо того, чтобы указывать имя файла, который будет разделен в команде split, мы даём простое – (тире) (после 4G, где у нас было имя входного файла в нашем предыдущем примере). Единственное тире — это дескриптор, означающий «стандартный ввод».

Другими словами, команда dd выдаёт поток данных в стандартный вывод (так как не указан файл для сохранения), а программа split принимает этот поток байтов на стандартный ввод, а не из файла. Любые параметры, которые вы хотите передать в dd (размер блока, количество и т. д. идут перед трубой).

Когда у нас есть образ, тот же метод с использованием cat позволит нам собрать его для хеширования или анализа, как мы это сделали с разделёнными образами выше.

Для практики вы можете использовать небольшой USB-накопитель, если он у вас есть, и попробовать этот метод на этом устройстве, разделив его на разумное количество частей. Вы можете использовать любой образец диска, не забудьте заменить наш узел устройства в следующей команде на /dev/sdx (где x — это ваш флэш-накопитель или другой носитель). Сначала получите хэш, чтобы вы могли сравнить разделённые файлы и оригинал и убедиться, что разделение ничего не меняет.

В следующем примере используется USB-накопитель ёмкостью 2 ГБ, который произвольно разделен на разделы размером 512 МБ. Следуйте командам и экспериментируйте с параметрами, наблюдая за изменениями в конечном результате. Это лучший способ учиться. Мы начнём с идентификации флэш-диска с помощью lsscsi, как только он будет подключён (вывод сокращён для удобства чтения):

lsscsi
sha1sum /dev/sdb
dd if=/dev/sdb | split -d -a3 -b512M - thumb.split.
ls -lh thumb.split.*| sha1sum
cat thumb.split.*| sha1sum

Глядя на вывод вышеуказанных команд, мы сначала видим, что подключенный флэш-накопитель идентифицируется как универсальный USB-накопитель. Затем мы на лету хэшируем устройство, образ и разбиваем его с помощью dd, а затем проверяем хеш. Мы находим один и тот же хеш для диска, для разделённых образов, «скомпонованных» вместе, и для вновь собранного образа.

:/>  Командная строка в Windows 7 и как ее вызвать

Ищем решение

Очевидно, чтобы избавиться от всех этих проблем, надо как-то привести их к единообразию.

И вот тут начинается самое интересное:

# -*- coding: utf-8 -*-
>>> import sys
>>> import locale
>>> print sys.getdefaultencoding()
ascii
>>> print locale.getpreferredencoding() # linux
UTF-8
>>> print locale.getpreferredencoding() # win32/rus
cp1251
# и самое интересное:
>>> print sys.stdout.encoding # linux
UTF-8
>>> print sys.stdout.encoding # win32
cp866


Ага! Оказывается «система» у нас живёт вообще в ASCII. Как следствие — попытка по-простому работать с вводом/выводом заканчивается «любимым» исключением

UnicodeEncodeError/UnicodeDecodeError

Кроме того, как замечательно видно из примера, если в linux у нас везде utf-8, то в Windows — две разных кодировки — так называемая ANSI, она же cp1251, используемая для графической части и OEM, она же cp866, для вывода текста в консоли. OEM кодировка пришла к нам со времён DOS-а и, теоретически, может быть также перенастроена специальными командами, но на практике никто этого давно не делает.

До недавнего времени я пользовался распространённым способом исправить эту неприятность:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# ==============
#      Main script file
# ==============
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
# или
import locale
sys.setdefaultencoding(locale.getpreferredencoding())
# ...


И это, в общем-то, работало. Работало до тех пор, пока пользовался

print

-ом. При переходе к выводу на экран через

logging

всё сломалось.

Угу, подумал я, раз «оно» использует кодировку по-умолчанию, — выставлю-ка я ту же кодировку, что в консоли:

sys.setdefaultencoding(sys.stdout.encoding or sys.stderr.encoding)


Уже чуть лучше, но:

Присмотревшись к первому примеру, нетрудно заметить, что так желаемую кодировку «cp866» можно получить только проверив атрибут соответствующего потока. А он далеко не всегда оказывается доступен.

Вторая часть задачи — оставить системную кодировку в utf-8, но корректно настроить вывод в консоль.


Для индивидуальной настройки вывода надо переопределить обработку выходных потоков примерно так:

import sys
import codecs
sys.stdout = codecs.getwriter('cp866')(sys.stdout,'replace')

Этот код позволяет убить двух зайцев — выставить нужную кодировку и защититься от исключений при печати всяких умляутов и прочей типографики, отсутствующей в 255 символах cp866.

Осталось сделать этот код универсальным — откуда мне знать OEM кодировку на произвольном сферическом компе? Гугление на предмет готовой поддержки ANSI/OEM кодировок в python ничего разумного не дало, посему пришлось немного вспомнить WinAPI

UINT GetOEMCP(void); // Возвращает системную OEM кодовую страницу как число
UINT GetANSICP(void); // то же для ANSI кодовой странцы

… и собрать всё вместе:

# -*- coding: utf-8 -*-
import sys
import codecs

def setup_console(sys_enc="utf-8"):
    reload(sys)
    try:
        # для win32 вызываем системную библиотечную функцию
        if sys.platform.startswith("win"):
            import ctypes
            enc = "cp%d" % ctypes.windll.kernel32.GetOEMCP() #TODO: проверить на win64/python64
        else:
            # для Linux всё, кажется, есть и так
            enc = (sys.stdout.encoding if sys.stdout.isatty() else
                        sys.stderr.encoding if sys.stderr.isatty() else
                            sys.getfilesystemencoding() or sys_enc)

        # кодировка для sys
        sys.setdefaultencoding(sys_enc)

        # переопределяем стандартные потоки вывода, если они не перенаправлены
        if sys.stdout.isatty() and sys.stdout.encoding != enc:
            sys.stdout = codecs.getwriter(enc)(sys.stdout, 'replace')

        if sys.stderr.isatty() and sys.stderr.encoding != enc:
            sys.stderr = codecs.getwriter(enc)(sys.stderr, 'replace')

    except:
        pass # Ошибка? Всё равно какая - работаем по-старому...

Как разбить файлы на тома определённого размера


Если вы хотите разбить файлы по размеру, то используйте опцию -C (файлы будут разбиты по строкам, разрывов строк не будет)

split -C 20m --numeric-suffixes ВХОДНОЙ_ФАЙЛ ВЫХОДНОЙ_ПРЕФИКС

Это команда создаёт файлы вида ВЫХОДНОЙ_ПРЕФИКС01 ВЫХОДНОЙ_ПРЕФИКС02 ВЫХОДНОЙ_ПРЕФИКС03 … каждый с максимальным размером в 20 мегабайт.

Команда split обычно работает со строками ввода (то есть из текстового файла). Но если мы используем параметр -b, мы заставляем split рассматривать файл как двоичный ввод, а строки игнорируются. Мы можем указать размер файлов, которые мы хотим, вместе с префиксом, который мы хотим для выходных файлов. split также может использовать параметр -d, чтобы дать нам числовую нумерацию (*.01 , *.02 , *.03 и т. д.) для выходных файлов, а не алфавитную, которая применяется по умолчанию (*.aa , *.ab , *.ac, и т.д.). Параметр -a указывает длину суффикса. Команда выглядит так:

split -d -a ЧИСЛО -b РАЗМЕРG ФАЙЛ_ДЛЯ_РАЗБИВКИ ПРЕФИКС_ВЫХОДНЫХ_ФАЙЛОВ

где ЧИСЛО — длина расширения (или суффикса), которое мы будем использовать, а РАЗМЕР — это размер результирующих файлов с модификатором единиц (K, M, G и т. д.). К примеру, разделим образ диска на файлы размером 4 ГБ с помощью следующей команды (размер последнего файла будет соответствовать оставшейся части тома, если он не является точно кратным выбранному вами размеру):

split -d -a 3 -b 4G case1.disk1.raw case1.disk1.split.

Это приведёт к созданию группы файлов (размером 4 ГБ), каждый из которых будет назван префиксом case1.split1, как указано в команде, за которым следует .000, .001, .002 и т. д. Параметр -a с 3 указывает, что мы хотим, чтобы расширение было не менее 3 цифр.

Как сменить кодировку utf-8 в cmd windows?

Файл должен выводиться в utf-8, а в консоли – 866, в итоге, в браузере отображаются ромбы.

:/>  Как изменить ПАРОЛЬ на компьютере для windows 7, 8, 10, XP - как поменять пароль, если забыл старый

После команды chcp 65001 ничего не поменялось.

Поскольку в консоли используется кодовая страница 866, то если в реестре поменять значение REG_SZ-параметра “866” под ключом [HKLMSYSTEMCurrentControlSetControlNlsCodePage] с “C_866.nls” (по умолчанию) на иное, то и кодировка в cmd также должна измениться.

Но у меня в CodePage таких файлов нет. Есть типы REG.SZ по умолчанию и 4 файла с номерами 932 936 949 950.

Вариант постоянно изменять в консоли chcp не подходит, но и не работает. Lucida console подключен в консоли.
Cygwin64 Terminal и Gitbash не запускает python server

Какие-то ещё есть варианты?

generate_all.py

# coding: utf-8

from horoscope import generate_prophecies
from datetime import datetime as dt


def generate_page(head, body):
    page = f"<html>{head}{body}</html>"
    return page


def generate_head(title):
    head = f"""<head>
    <meta charset='utf-8'>
    <title>{title}</title>
    </head>
    """
    return head


def generate_body(header, paragraphs):
    body = f"<h1>{header}</h1>"
    for p in paragraphs:
        body = body   f"<p>{p}</p>"
    return f"<body>{body}</body>"


def save_page(title, header, paragraphs, output="index.html"):
    fp = open(output, "w")
    today = dt.now().date()
    page = generate_page(
        head=generate_head(title),
        body=generate_body(header=header, paragraphs=paragraphs)
    )
    print(page, file=fp)
    fp.close()

#####################


today = dt.now().date()

save_page(
    title="Гороскоп на сегодня",
    header="Что день "   str(today)   " готовит",
    paragraphs=generate_prophecies(),
)

horoscope.py

import random
times = ['утром', 'днем', 'вечером', 'ночью', 'после обеда', 'перед сном']
advices = ['ожидайте', 'предостерегайтесь', 'будьте открыты для']
promises = ['гостей из забытого прошлого', 'встреч со старыми знакомыми',
            'неожиданного праздника', 'приятных перемен']

def generate_prophecies(total_num=5, num_sentences=3):
    prophecies = []
    for i in range(total_num):
        forecast = ''
        for j in range(num_sentences):
            t = random.choice(times)
            a = random.choice(advices)
            p = random.choice(promises)
            full_sentence = f'{t.title()} {a} {p}.'
            if j != num_sentences - 1:
                full_sentence = full_sentence   ' '
    forecast = forecast   full_sentence
    prophecies.append(forecast)
    return prophecies

При запуске кода через powershell и сервера в этой же директории python -m http.server) из консоли win (python generate_all.py из командной строки или Ctrl B в
саблайме) в этой же папке генерируется файл index.html, и в браузере можно увидеть ромбы.

Все файлы в utf-8,

Программа enca для определения кодировки файла

Утилита enca определяет кодировку текстовых файлов и, если нужно, конвертирует их.

Установим программу enca:

sudo apt install enca


Примеры использования:

enca mypoem_draft.txt
enca mynovel.txt

В этот раз для обоих файлов кодировка определена верно.

Запуск команды без опции выводит что-то вроде:

MS-Windows code page 1251
  LF line terminators


Это удобно для чтения людьми. Для использования вывода программы в скриптах есть опция -e, она выводит только универсальное имя, используемое в enca:

enca -e mypoem_draft.txt
CP1251/LF

Если вам нужно имя, которое используется для названия кодировок в iconv, то для этого воспользуйтесь опцией -i:

enca -i mypoem_draft.txt
CP1251

Для вывода предпочитаемого MIME имени кодировки используется опция -m:

enca -m mypoem_draft.txt
windows-1251


Для правильного определения кодировки программе enca нужно знать язык файла. Она получает эти данные от локали. Получается, если локаль вашей системы отличается от языка документа, то программа не сможет определить кодировку.

Язык документа можно явно указать опцией -L:

enca -m -L russian mypoem_draft.txt

Чтобы узнать список доступных языков наберите:

enca --list languages


Вы увидите:

belarusian: CP1251 IBM866 ISO-8859-5 KOI8-UNI maccyr IBM855 KOI8-U
 bulgarian: CP1251 ISO-8859-5 IBM855 maccyr ECMA-113
     czech: ISO-8859-2 CP1250 IBM852 KEYBCS2 macce KOI-8_CS_2 CORK
  estonian: ISO-8859-4 CP1257 IBM775 ISO-8859-13 macce baltic
  croatian: CP1250 ISO-8859-2 IBM852 macce CORK
 hungarian: ISO-8859-2 CP1250 IBM852 macce CORK
lithuanian: CP1257 ISO-8859-4 IBM775 ISO-8859-13 macce baltic
   latvian: CP1257 ISO-8859-4 IBM775 ISO-8859-13 macce baltic
    polish: ISO-8859-2 CP1250 IBM852 macce ISO-8859-13 ISO-8859-16 baltic CORK
   russian: KOI8-R CP1251 ISO-8859-5 IBM866 maccyr
    slovak: CP1250 ISO-8859-2 IBM852 KEYBCS2 macce KOI-8_CS_2 CORK
   slovene: ISO-8859-2 CP1250 IBM852 macce CORK
 ukrainian: CP1251 IBM855 ISO-8859-5 CP1125 KOI8-U maccyr
   chinese: GBK BIG5 HZ
      none:

Функции перекодировки

В Windows API есть две (а точнее, четыре пары) функции, осуществляющие перекодировку OEM <->ANSI (так сказано в документации). Проще говоря, в контексте рассматриваемого вопроса, это перекодировка между cp866 (OEM) и cp1251 (ANSI).

«Опасные» функции без контроля длины строки:

В качестве параметров получают указатели на входной и выходной буферы. Нулевой символ считается концом входной строки.

«Безопасные» функции с контролем длины строки:

В качестве параметров получают указатели на входной и выходной буферы и количество символов для входной строки. Нулевые символы не считаются концом строки. Преобразуется указанное количество символов.

На самом деле перечисленные функции являются макросами, которые раскрываются, к примеру для CharToOemBuff , в CharToOemBuffW (при поддержке Unicode) или в CharToOemBuffA (ANSI — без поддержки Unicode). Но о таких тонкостях обычно можно не вспоминать.

Эти функции полезны, когда вывод идёт в одной кодировке, а ввод — в другой. Такая ситуация складывается, например, при использовании только функции setlocale(): вывод осуществляется в cp1251, а ввод — в cp866. Следуя первому правилу, введенную строку надо преобразовать к cp1251. Для этого используется OemToCharBuff().

Также эти функции могут быть использованы перед выводом строки в файл или после ввода строки из файла, в случае, если кодировки не совпадают.

P. S. Не судите строго — это мой первый опыт в написании статьи. Я так посмотрел, люди пишут, а чем я хуже? Тем более, что появилось чем поделиться. А оказалось, что это трудно. И написать, и ошибки проверить, и иллюстрации подготовить.

На написание статьи меня сподвиг вопрос о «кракозябрах в XP». Под это дело из руин даже был извлечен старый комп с XP. И оказалось, что проблема действительно имеет место. Пришлось провести небольшое исследование, результаты которого я здесь и изложил.

С уважением, Макар.

Задача вторая. раскрашиваем вывод


Насмотревшись на отладочный вывод Джанги в связке с werkzeug, захотелось чего-то подобного для себя.

выдаёт несколько проектов разной степени проработки и удобности — от простейшего наследника

logging.StreamHandler

, до некоего набора, при импорте автоматически подменяющего стандартный StreamHandler.

Попробовав несколько из них, я, в итоге, воспользовался простейшим наследником StreamHandler, приведённом в одном из комментов на Stack Overflow и пока вполне доволен:

class ColoredHandler( logging.StreamHandler ):
    def emit( self, record ):
        # Need to make a actual copy of the record
        # to prevent altering the message for other loggers
        myrecord = copy.copy( record )
        levelno = myrecord.levelno
        if( levelno >= 50 ): # CRITICAL / FATAL
            color = 'x1b[31;1m' # red
        elif( levelno >= 40 ): # ERROR
            color = 'x1b[31m' # red
        elif( levelno >= 30 ): # WARNING
            color = 'x1b[33m' # yellow
        elif( levelno >= 20 ): # INFO
            color = 'x1b[32m' # green
        elif( levelno >= 10 ): # DEBUG
            color = 'x1b[35m' # pink
        else: # NOTSET and anything else
            color = 'x1b[0m' # normal
        myrecord.msg = (u"%s%s%s" % (color, myrecord.msg, 'x1b[0m')).encode('utf-8')  # normal
        logging.StreamHandler.emit( self, myrecord )

Однако, в Windows всё это работать, разумеется, отказалось. И если раньше можно было «включить» поддержку ansi-кодов в консоли добавлением «магического» ansi.dll из проекта symfony куда-то в недра системных папок винды, то, начиная (кажется) с Windows 7 данная возможность окончательно «выпилена» из системы. Да и заставлять юзера копировать какую-то dll в системную папку тоже как-то «не кошерно».

:/>  Лучшая читалка fb2 книг для компьютера: ТОП-10 приложений

Снова обращаемся к гуглу и, снова, получаем несколько вариантов решения. Все варианты так или иначе сводятся к подмене вывода ANSI escape-последовательностей вызовом WinAPI для управления атрибутами консоли.

Побродив некоторое время по ссылкам, набрёл на проект colorama. Он как-то понравился мне больше остального. К плюсам именно этого проекта ст́оит отнести, что подменяется весь консольный вывод — можно выводить раскрашенный текст простым print u”x1b[31;40mЧто-то красное на чёрномx1b[0m” если вдруг захочется поизвращаться.

Сразу замечу, что текущая версия 0.1.18 содержит досадный баг, ломающий вывод unicode строк. Но простейшее решение я привёл там же при создании issue.

Собственно осталось объединить оба пожелания и начать пользоваться вместо традиционных «костылей»:

# -*- coding: utf-8 -*-
import sys
import codecs
import copy
import logging

#: Is ANSI printing available
ansi = not sys.platform.startswith("win")

def setup_console(sys_enc='utf-8', use_colorama=True):
    """
    Set sys.defaultencoding to `sys_enc` and update stdout/stderr writers to corresponding encoding

    .. note:: For Win32 the OEM console encoding will be used istead of `sys_enc`
    """
    global ansi
    reload(sys)
    try:
        if sys.platform.startswith("win"):
#... код, показанный выше
        if use_colorama and sys.platform.startswith("win"):
            try:
                # пробуем подключить colorama для винды и взводим флаг `ansi`, если всё получилось
                from colorama import init
                init()
                ansi = True
            except:
                pass

class ColoredHandler( logging.StreamHandler ):
    def emit( self, record ):
        # Need to make a actual copy of the record
        # to prevent altering the message for other loggers
        myrecord = copy.copy( record )
        levelno = myrecord.levelno
        if( levelno >= 50 ): # CRITICAL / FATAL
            color = 'x1b[31;1m' # red
        elif( levelno >= 40 ): # ERROR
            color = 'x1b[31m' # red
        elif( levelno >= 30 ): # WARNING
            color = 'x1b[33m' # yellow
        elif( levelno >= 20 ): # INFO
            color = 'x1b[32m' # green
        elif( levelno >= 10 ): # DEBUG
            color = 'x1b[35m' # pink
        else: # NOTSET and anything else
            color = 'x1b[0m' # normal
        myrecord.msg = (u"%s%s%s" % (color, myrecord.msg, 'x1b[0m')).encode('utf-8')  # normal
        logging.StreamHandler.emit( self, myrecord )

Дальше в своём проекте, в запускаемом файле пользуемся:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from setupcon import setup_console
setup_console('utf-8', False)
#...

# или если будем пользоваться раскрашиванием логов
import setupcon
setupcon.setup_console()
import logging
#...
if setupcon.ansi:
    logging.getLogger().addHandler(setupcon.ColoredHandler())

На этом всё. Из потенциальных доработок осталось проверить работоспособность под win64 python и, возможно, добаботать ColoredHandler чтобы проверял себя на isatty, как в более сложных примерах на том же StackOverflow.

Итоговый вариант получившегося модуля можно забрать на dumpz.org

Ввод и вывод на консоль

Для корректного ввода и вывода кириллицы на консоль надо использовать пару функций: SetConsoleOutputCP() и SetConsoleCP(). Описания в MSDN здесь и здесь соответственно.

В качестве единственного параметра обеим функциям передается номер кодовой страницы. В нашем случае (кириллица) — это 1251.

Этот способ работает и для Windows XP, и для Windows 7. Опробовано с Dev-C 5.6.3 (компилятор TDM-GCC 4.8.1 32-bit) и MS Visual Studio 2021.

Следующая тестовая программа демонстрирует вывод кириллицы на консоль, ввод кириллической строки с консоли, контрольный вывод введенной строки, сравнение введенной строки с эталонной и вывод введенной строки в файл.

Исходный текст в кодировке cp1251:

#include <iostream>
#include <iomanip>
#include <windows.h>

#include <cstring>
#include <fstream>

using namespace std;

char str[128];
char pattern[] = "йцукен";

int main(int argc, char** argv) 
{
    //setlocale(LC_ALL, "Russian");
    SetConsoleOutputCP(1251);
    SetConsoleCP(1251);

    cout << "Привет!" << endl;
    for (int i = 32; i < 256; i  ) {
        if (i % 8 == 0) 
            cout << endl;
        if (i == 128) 
            cout << endl;
        cout << setw(5) << i << setw(3) << (char)i; 
    }
    cout << endl << "Введите строку "йцукен": ";
    cin >> str;
    cout << "Введено: " << str << endl;
    cout << "strings " << (strcmp(str, pattern) == 0 ? "" : "NOT ") << "identical" << endl;

    ofstream fout("cp-test.txt");
    fout << str << endl;
    fout.close();

    cin.get();
    cin.get();
    return 0;
}

Эта программа также удобна для экспериментов с различными кодовыми таблицами и их сочетаниями.

Для практических целей можно использовать шаблон:

#include <iostream>
//#include <clocale>    // может быть не обязательным - зависит от компилятора
#include <windows.h>

int main(int argc, char** argv) 
{
    //setlocale(LC_ALL, "Russian");
    SetConsoleOutputCP(1251);
    SetConsoleCP(1251);

    // здесь должна быть программа

    return 0;
}

Здесь я намеренно оставил закомментированный вызов setlocale(LC_ALL, “Russian”);. На ввод-вывод кириллицы он уже не влияет, но может потребоваться для других национальных настроек (разделитель дробной части числа, формат даты, времени и пр.)

Оставьте комментарий

Adblock
detector