1 (изменено: wisgest, 2013-06-27 11:10:46)

Тема: CMD/BAT: Перекодировка текстовых файлов

CMD/BAT: перекодировка текста dos866↔win1251:

The gray Cardinal пишет:

Есть немало консольных утилит для перекодировки текста, но многие забывают про встроенные возможности.

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

chcp XXX
type in.txt>out.txt

Не обязательно совсем так просто: допускалась, например, необходимость нескольких вложенных вызовов CMD.EXE — главное, обойтись небольшим числом обращений к утилите CHCP.COM, а не дёргать её для каждой строки. К сожалению, мне ничего не удалось, хотя я по прежнему допускаю существование решения на этом пути.

Так что решение от 01MDM имеет полное право на существование в Коллекции, хотя и не лишено недостатков, как неустранимых (FOR /F пропускает пустые строки; есть сложности со спецсимволами вплоть до угрозы инъекции кода), так и устранимых, которые следовало бы убрать, подправив тему без создания новых сообщений (не помню, то ли не обрабатываются пробелы в начале строк, то ли непустые строки не содержащие ничего кроме пробелов). Но сейчас речь не об этом.

То что не получилось одним махом (командой TYPE) можно сделать двумя: перекодировкой исходного файла в промежуточный файл в UTF-16, а затем промежуточного — в файл в нужной кодировке. В качестве кодировок исходного и конечного файла могут быть любые однобайтные кодировки, а также UTF-8 без BOM. В основе такого решения лежит соединение вместе уже упоминавшихся мною приёмов по перекодировке файлов в/из UTF-16 с помощью команды TYPE.

Вот пример (без необходимых в полевых условиях проверок), раскрывающий эту мысль (этот код содержит непечатные знаки, не копируйте его, а берите из присоединённого файла!):

@echo off
set /p IN=Исходный файл: 
set /p IN_CP=Его кодировка: 
set /p OUT=Выходной файл: 
set /p OUT_CP=Желаемая кодировка: 
for /f "tokens=2 delims=:" %%i in ('chcp.com') do set CP=%%i
::в следующей строке выводятся байты \xFF\xFE (BOM):
set /p p= ?<nul >utf-16.tmp
(
chcp.com %IN_CP%>nul
cmd.exe /u /c type %IN%>>utf-16.tmp
chcp.com %OUT_CP%>nul
cmd.exe /c type utf-16.tmp>%OUT%
chcp.com %CP%>nul
)
del utf-16.tmp

Может возникнуть вопрос: зачем здесь несколько команд объединены круглыми скобками в одну составную?
Отвечаю: В качестве кодировки как входного так и выходного файлов могут выступать не только однобайтные кодировки, но и UTF-8 (кодовая страница 65001), а работа командных файлов при переключении на неё, по крайней мере в более ранних изданиях Windows, например в XP, имеет одну неприятную особенность — они тихо завершают работу на следующей же команде, но текущая (в том числе, составная) команда всё-таки выполняется и если в конце неё переключится обратно на однобайтную кодировку, то вылета не произойдёт. Но переключение кодировок в составной команде не влияет на входящие в неё внутренние команды обработчика, поэтому, чтобы воспользоваться её плодами, необходимо команду вызывать через новую копию CMD.EXE с ключом /C. Это одна из причин, по которой таким образом вызывается вторая TYPE, но, собственно говоря, её всё-равно следовало бы вызывать таким образом, если учесть исчезающе малую возможность, что командный файл вызван из CMD.EXE, уже запущенного с ключом /U.

Еще по поводу UTF-8: Если она используется во входном файле, то он не должен содержать BOM, иначе в начале выходного будет лишний символ и как его обрезать мне на ум не приходит. Если она используется для выходного файла, то он создаются без BOM, но это легко обойти тем же путем что и при создании промежуточного файла в UTF-16.

(Что-то похожее мною уже затрагивалось.)

Post's attachments

recode.zip 402 b, 46 downloads since 2013-06-24 

You don't have the permssions to download the attachments of this post.

2 (изменено: wisgest, 2013-06-25 16:38:47)

Re: CMD/BAT: Перекодировка текстовых файлов

wisgest пишет:

Это одна из причин, по которой таким образом вызывается вторая TYPE, но, собственно говоря, её всё-равно следовало бы вызывать таким образом, если учесть исчезающе малую возможность, что командный файл вызван из CMD.EXE, уже запущенного с ключом /U.

Несущественное замечание: на самом деле, для полного учёта такой возможности следовало бы добавить ещё «cmd.exe /c » в начало строки с непечатными знаками.