web-dev-qa-db-ja.com

UTF-8コードページ識別子(65001)は他のコンピューターとは異なりますか?

私は最近、簡単な1行のバッチファイルを作成する方法を友人に説明しようとしました。

subst t: "X:\Example"

何年も正常に動作している私のマシンでは、問題が発生しました。名前に非ASCII文字(正確にはトルコ語の文字ıとç)が含まれていて、正しく認識されませんでした。

これに対する簡単な解決策は、私が追加することです

chcp 65001

ファイルの先頭で、アクティブなコードページをUTF-8に変更します。

しかし、これはうまくいきませんでした。彼らのコンピュータでは、これにより、それを実行していたコマンドShellがクラッシュしました。私は彼らにいくつかの異なる値を試してもらいました。 65000はクラッシュしましたが、10000はクラッシュせず、試した値より下のすべての値も同様に機能しましたが、コンピューター上の同じ値と同じコードページに対応していませんでした。デフォルトのコードページも異なっていました(私のコンピューターの850ではなく857。MSDNによると、857はトルコのコードページであり、850は西ヨーロッパのページであるため、これは理にかなっています)。

一部のコードページはコンピューターごとに変更される可能性があることは知っていますが、MSDNページには、他のページが変更される可能性があるため、UTF-8を使用する必要があると明示的に記載されています(ただし、変更の方法と時期に関するドキュメントが不足しています)。

それは間違っていますか? 65001の値も変更できますか?もしそうなら、なぜそれがクラッシュを引き起こすのでしょうか?最悪の場合、「無効なコードページ」について文句を言うべきではありませんか?そして、それが変更された場合、それを取得するために使用する値をどのように見つけることができますか、または非ASCII文字を受け入れるために他にどのように取得できますか?

私はWindows10を英語で使用しています(Windows 8.1イタリア語がプリインストールされています)が、友人はWindows7トルコ語を使用しています。

3
Annonymus

基本的に、Windows cmd(およびバッチスクリプトインタープリターも)は、(現在の)アクティブなコードページとバッチスクリプトエンコーディングの適合性に依存しています。たとえば、スクリプトをNotepadからいわゆる[〜#〜] ansi [〜#〜]エンコーディングで保存する場合(これは Windowsシステムロケール )に強く依存しているため、対応するコードページで実行する必要があります。 National Language Support(NLS)APIリファレンス を参照してください。

  • English (US) :[〜#〜] ansi [〜#〜]はACP 1252(CP 437)に対応します。
  • English (UK) :[〜#〜] ansi [〜#〜]はACP 1252(CP 850)に対応します。
  • Turkish :[〜#〜] ansi [〜#〜]はACP 1254(CP 857)に対応します。
  • Central Europe:[〜#〜] ansi [〜#〜]はACP 1250(CP 852)などに対応します。

あなたの推定は正しいです:

これに対する簡単な解決策は、ファイルの先頭にchcp 65001を追加することですアクティブなコードページをUTF-8に変更します。 …しかし、これはうまくいきませんでした。

残念ながら、Windows cmdもバッチインタープリターも バイトオーダーマーク を気にせず、現在アクティブなコードページを無視して有効な文字として扱います。
したがって、UTF-8エンコードされたファイルの最初の行(あなたの場合はCHCP 65001コマンド)は汚れています BOMが存在する場合。このようなdingyコマンドを実行しようとすると、エラーメッセージ' CHCP' is not recognized as an internal or external command, operable program or batch file(errorlevel 9009)が表示されます。

解決策:スクリプトUTF-8エンコードをBOMなしで保存します。
それができない場合の回避策(Notepadは常にBOMを書き込むため):スクリプトの最初の行としてダミーコマンドを使用します。次のように:

@rem if this line is visibly executed then BOM is present >NUL 2>&1
@echo OFF
    rem save current code page to the `_chcp` variable
for /F "tokens=2 delims=:" %%G in ('chcp') do set "_chcp=%%G"
    rem change active code page to UTF-8 (silently)
CHCP 65001 >NUL
    rem echo this is UTF-8 encoded batch file %~nx0
echo(
subst t: "D:\bat\Unusual Names\Türkçe (Türkiye)\çğüşöıĞÜİŞÇÖ"
subst
dir /B /S t:\*.txt
subst t: /D
echo(
echo(  works as well for characters from Unicode Basic Multilingual Plane
subst t: "D:\bat\Unusual Names\CJK\中文(繁體)"
subst
dir /B /S t:\*.txt
subst t: /D
echo(
echo(  works even for characters from Unicode Supplementary Multilingual Plane
subst t: "D:\bat\Unusual Names\????????????????????????????????????????????????????????"
subst
dir /B /S t:\*.txt
subst t: /D
    rem set active code page back to previously saved value (verbose)
echo(
CHCP %_chcp%

出力

==> utf8.bat

==> ´╗┐@rem if this line is visibly executed then BOM is present  1>NUL 2>&1

T:\: => D:\bat\Unusual Names\Türkçe (Türkiye)\çğüşöıĞÜİŞÇÖ
t:\ĞÜİŞÇÖçğüşöı.txt

  works as well for characters from Unicode Basic Multilingual Plane
T:\: => D:\bat\Unusual Names\CJK\中文(繁體)
t:\chinese traditional.txt

  works even for characters from Unicode Supplementary Multilingual Plane
T:\: => D:\bat\Unusual Names\????????????????????????????????????????????????????????
t:\Mathematical Bold Script.txt

Active code page: 852

最後に、次のように more command を使用して、スクリプトから最初の行(BOMを含む)を削除できます(chcp 65001を実行する前にmore +1 …に注意してください)。

==> chcp 65001
Active code page: 65001

==> more +1 utf8.bat > utf8noBOM.bat

==> utf8noBOM.bat

T:\: => D:\bat\Unusual Names\Türkçe (Türkiye)\çğüşöıĞÜİŞÇÖ
t:\ĞÜİŞÇÖçğüşöı.txt

  works as well for characters from Unicode Basic Multilingual Plane
T:\: => D:\bat\Unusual Names\CJK\中文(繁體)
t:\chinese traditional.txt

  works even for characters from Unicode Supplementary Multilingual Plane
T:\: => D:\bat\Unusual Names\????????????????????????????????????????????????????????
t:\Mathematical Bold Script.txt

Active code page: 65001

==>
2
JosefZ