1 (изменено: Rumata, 2021-10-16 04:14:57)

Тема: CMD/BAT: Определение кодировки файла (определение 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

Я намеренно каждое исправление фиксировал отдельным коммитом.

( 2 * b ) || ! ( 2 * b )

2 (изменено: Rumata, 2021-10-15 00:56:39)

Re: CMD/BAT: Определение кодировки файла (определение BOM)

Внесены изменения

Rumata пишет:

2021-10-14
-- несколько косметических изменений
-- "молчаливое" удаление временного файла
-- определение кодировки оформлено как подпрограмма
-- корректно сообщает о несуществующих файлах, пустых файлах и директориях
-- переименовал скрипт: "bom_file.bat" -> "file-detect-bom.bat"

( 2 * b ) || ! ( 2 * b )