Тема: CMD/BAT: Определение кодировки файла (определение BOM)
**********************
Скрипт имеет ограничение: он умеет определять кодировку только по наличию BOM. Для UTF-8 его наличие необязательно. Поэтому UTF-8 файлы без BOM не определяются. В процессе изобретения этого скрипта был найден еще один вариант. Он приведен в этой же теме ниже.
**********************
Сходная тема в соседнем разделе WSH: Определение кодировки файла
Используются только возможности интерпретатора и стандартная команда FC для сравнения двух файлов. Хитрость заключается в двоичном сравнении специально созданного временного файла с искомым. Идея не моя, я ее вычитал где-то на форуме https://www.dostips.com/.
Пример использования:
>powershell -c "write \"In math the Greek letter $([char]0x03C0) stands for 3.1415926\" | out-file -encoding utf8 example-file"
>type example-file
я╗┐In math the Greek letter ╧А stands for 3.1415926
>file-detect-bom.bat example-file
example-file: UTF-8
>file-detect-bom.bat -b example-file
UTF-8
Актуальну версию можно найти здесь: https://github.com/ildar-shaimordanov/c … ct-bom.bat
::Usage: file-detect-bom [OPTIONS] FILE...
::
::Detect the Byte Order Mark (BOM) in FILEs.
::
:: -b, --brief Don't prepend filenames to output
@echo off
setlocal enabledelayedexpansion
set "bom_brief="
if /i "%~1" == "-b" set "bom_brief=1"
if /i "%~1" == "--brief" set "bom_brief=1"
if defined bom_brief shift /1
if "%~1" == "" goto :print_usage
:: ========================================================================
:: The following settings are based on information from the table
:: https://en.wikipedia.org/wiki/Byte_order_mark#Byte_order_marks_by_encoding
set "bom_val_EFBBBF=UTF-8"
set "bom_val_FEFF=UTF-16BE"
set "bom_val_FFFE=UTF-16LE"
set "bom_val_0000FEFF=UTF-32BE"
set "bom_val_FFFE0000=UTF-32LE"
set "bom_val_2B2F76=UTF-7"
set "bom_val_F7644C=UTF-1"
set "bom_val_DD736673=UTF-EBCDIC"
set "bom_val_0EFEFF=SCSU"
set "bom_val_FBEE28=BOCU-1"
set "bom_val_84319533=GB-18030"
:: ========================================================================
set "bom_cmpfile=%TEMP%\bom_cmpfile"
set /p "=@@@@" <nul >"%bom_cmpfile%"
:bom_begin_loop
if "%~1" == "" (
del /f /q "%bom_cmpfile%" 2>nul
goto :EOF
)
for %%f in ( "%~1" ) do (
call :detect_type "%%~f"
if defined bom_brief (
if defined bom_found echo:!bom_found!
) else (
echo:%%~f: !bom_found!
)
)
shift /1
goto :bom_begin_loop
:: ========================================================================
:print_usage
for /f "usebackq tokens=* delims=:" %%s in ( "%~f0" ) do (
if /i "%%s" == "@echo off" goto :EOF
echo:%%s
)
goto :EOF
:: ========================================================================
:detect_type
set "bom_found="
set "bom_srcfile=%~1"
if not exist "%~1" (
echo:File not found: "%~1">&2
exit /b 1
)
if exist "%~1\" (
set "bom_found=directory"
goto :EOF
)
if %~z1 equ 0 (
set "bom_found=empty"
goto :EOF
)
set "bom_bytes="
for /f "tokens=1,2,3,4 delims=: " %%a in ( '
fc /b "%bom_cmpfile%" "%~1" ^| findstr /n /r "^00*[0-3]"
' ) do (
set /a bom_diff=%%a-%%b
if !bom_diff! equ 2 set "bom_bytes=!bom_bytes!%%d"
)
for /l %%n in ( 8, -2, 4 ) do for %%s in ( bom_val_!bom_bytes:~0^,%%n! ) do (
set "bom_found=!%%s!"
if defined bom_found goto :EOF
)
goto :EOF
:: ========================================================================
:: EOF
2021-10-14
-- несколько косметических изменений
-- "молчаливое" удаление временного файла
-- определение кодировки оформлено как подпрограмма
-- корректно сообщает о несуществующих файлах, пустых файлах и директориях
-- переименовал скрипт: "bom_file.bat" -> "file-detect-bom.bat"
2021-10-13
После первой публикации нашел небольшой баг: если кодировка файла не определена, то следущий файл отображается в этой же строке. Например:
Z:>bom_file ascii_file utf8_file
ascii_file: utf8_file: UTF-8
Сейчас это исправлено.
Потом мне захотелось сделать скрипт еще лучше и я изменил несколько мест:
-- немного усложнил, но сделал более строгим сбор первых, не более 4 последовательных байт
-- оптимизировал фрагмент определения кодировки
-- упростил вывод результата
2021-10-11
Первая публикация
Историю изменений можно посмотреть по этим ссылкам:
-- https://github.com/ildar-shaimordanov/c … m_file.bat.
-- https://github.com/ildar-shaimordanov/c … ct-bom.bat
Я намеренно каждое исправление фиксировал отдельным коммитом.