2010年8月17日火曜日

文字列操作関数使用時の注意点まとめ - AWK

AWKの文字列操作関数と関連機能

**** 処理系共通の注意点
o 「\」は、特殊文字を書く為のキーワードです。(例。「\n」は改行コード)
   + 文字列の中に「\」を含めたい時は、「\\」と書きます。
   + 但し、Gawkの gensub 関数を使う時は、「\\数字」が意味を持つ場所もありますので、注意します。
o 特定の関数で、「&」が特別な意味を持つ場所があります。(gsub / sub
   + 「&」が特別な意味を持つ場所で「&」を含めたい時は、「\\&」と書きます。

o gsub 関数は、対象文字列の途中に改行コードが含まれていると、改行コード以降は置き換えないみたいです。
   + 少なくとも、正規表現の「^」(= チルダ)は文字列の先頭のみを置き換えます。
o split 関数の区切り文字で「\」自身を指定する時、"[\\]" と書く事は出来ません。
   + "[\\\\]" もしくは "\\" や "\\\\" を使います。

o 実数を文字列操作関数に渡すと、本処理の前に、7桁目を丸める傾向がありました。
   + 変換する桁数を簡単に増やしたい時は、変数CONVFMTを使います。
   + もしくは、sprintfを使って、特定の変数だけ有効桁数を変える事も出来ます。
   + 詳しくは、「数値から文字列にする時に、実数を7桁以上表示させる方法
o 文字列比較などの場面で、値を数値だと認識されてしまった時は、文字列化する必要があります。
   + 「v = v ""」のように、空文字を並べて書く方法
   + sprintf関数を使う方法
   + 7桁以上の実数を表示したい時は、「数値から文字列にする時に、実数を7桁以上表示させる方法

o 漢字などの全角文字で原因不明のエラーになる場合
   + 最初に、文法誤りの可能性を疑います。
   + 多くの場合、AWKプログラムと入力ファイルの文字コードを適切にすると、解決します。
      + Windows版のmawkとオリジナルは、Shift-JIS以外は対応していません。
   + Gawkの場合、システムの言語設定を一時的に合わせる方法もあります。
      + Gawk on Windowsの場合は、オプションで設定する事が出来ます。
      + Windowsとは関係がありませんが、UNIXの言語設定について
         + 現在の言語設定を確認する方法は「locale = UNIXで地域設定(ロケール)について確認する方法
         + UNIXの場合、ウィンドウ1つに対して言語設定を変更する事が出来ます。
   + 16進数などの特殊文字を使って表現すると、回避出来る事があります。
   + 文字コードを自動判定するような処理系の場合は、コメントで回避出来るかもしれません。
      + 例えば、Shift-JISの場合は、# あいうえお を最初の方に入れるなど
      + これは、古いブラウザーに対する文字化け回避の手法です。文字コード特有の文字を入れる事で、誤判定を防ぐ効果があります。
--------
# あいうえお
BEGIN {
  print "テストです。";
}
--------



**** 特定の処理系に関する注意点
** Gawk系特有の動作
o Gawk on Windows (3.1.7)で測定した所、sprintfの動作が、mawkや下の方法の9倍程度遅かったです。測定結果は「速度比較。文字列の組み立て
   + 動作が遅いと思ったら、文字列(と数値)の連結を、文字列などを並べる方法に変えてみると、改善するかもしれません。間に半角空白を入れます。
--------
BEGIN {
  n = 39;
  name = "ミク";
  v = n "番の" name "さん。";
  # Gawkの場合、次の文よりもn倍速いです。v = sprintf("%d番の%sさん", n, name);

  print v;
}
--------


o この他、UTF-8ファイルの読み込み1行目で、文字列操作関数の返す値が変な時は、UNICODE特有の見えない文字(BOM)が悪さをしているかもしれません。詳しくは「GawkでUTF-8のファイルを読み込む時の注意点

** mawk系特有の動作
o 全角文字の場合、文字数をバイト数で数えます。
o Mawk for Windowsについては、全角文字に対応していない関数があります。(sub / gsub / toupperなど)
   + 例えば、「表」を「\\」(= \の事です)で検索すると、「表」の後半部分で一致します。

** オリジナルAWK特有の動作
o 全角文字の場合、文字数をバイト数で数えます。
o 処理系自体が、日本語に対応していないみたいです。
   + 例えば、v = "表ミクさん表表"; print v; で文字化けします。


==
関連ページ:
    ▼AWKの文字列操作関数と関連機能▼ABC順
    ▼AWKプログラムを書く▼ABC順
    ▼AWK
    ▼制作メモ
    > 文字列を組み立てる
    文字列から文字を1つずつ取り出す
    文字列中で使用出来る特殊文字
    +
    配列を使う時の注意点まとめ
(2011年8月22日追加。split関数の区切り文字に「\」を指定する方法)
(2010年10月28日追加。文字コードを自動判定する処理系が誤判定する時の回避案)
(2010年10月22日追加。特殊文字へのリンクと、全角文字でエラーになった時)
(2010年8月23日追加。「\」と「&」)

Gawkで、UTF-8のファイルからBOMを除去する方法 - AWK

AWKの入出力関数とコマンド実行機能
Gawkでは、文字コードがUTF-8のファイルを扱う時は、BOM(UNICODE特有の、見えない文字)が入っていてはいけません。
でも、Windows XPのメモ帳で、UTF-8のファイルをお手軽に作成すると、BOMが必ず入ります。
そこで、BOMを除去する方法について、調べてみました。


**** BOMが入る例
o Windows XP (SP3)のメモ帳で作成し、文字コード UTF-8で保存した時、1行目の先頭にBOM(16進数表記で、EF BB BF)が入ります。


**** 対策方法
o 漢字のような全角文字を一切使っていない場合は、UTF-8ではなく、普通に(ANSIで)保存すると、正しく動きました。
o 他のテキストエディターを使って、BOMを入れないようにする方法もあります。
   + さくらエディタなど、BOMの有無を選択出来るものを選びます。
o 下のようなプログラムを使って、事前にBOMを取り除いてからAWKプログラムを実行するようにする方法もあります。


**** Gawkを使ってBOMを除去する方法(の例)
o 大量のファイルを変換したい時に、便利です。
o 変換用プログラムを作る時のポイントは、2つあります。
   + AWKプログラムを書く時は、日本語を使わず、半角文字だけで書く事
   + メモ帳でのファイルの保存は、UTF-8ではなく、普通に(ANSIで)保存する事

** NoBom.awk -- BOMを除去するAWKプログラムを作ります。
   + エクスプローラーで.awkが表示されない時は、「ファイルの拡張子を変更可能にする方法
--------
{
  if (FNR == 1) {
    sub(/\xef\xbb\xbf/,"");
  }
  print;
}
--------

o 行末のセミコロンは、C言語の書き方に合わせました。無くても動きます。

** NoBom.bat -- 実行するバッチファイルを用意します。(例は、Windows用です)
o Gawk on Windows 3.1.7の場合。オプション「 -W ctype=UTF8」を追加します。
   + gawk.exeの部分は、実行したいAWKに置き換えて下さい。
   + このオプションは無くても問題ないみたいですが、念の為追加しました。
--------
if not exist in mkdir in
if not exist out mkdir out
cd in
for %%F in (*.*) do gawk.exe -W ctype=UTF8 -f ..\NoBom.awk "%%F" > ..\out\"%%F"
cd ..
pause
--------


o Gawk for Windows 3.1.6の場合
   + gawk.exeの部分は、実行したいAWKに置き換えて下さい。
--------
if not exist in mkdir in
if not exist out mkdir out
cd in
for %%F in (*.*) do gawk.exe -f ..\NoBom.awk "%%F" > ..\out\"%%F"
cd ..
pause
--------


** 上のバッチファイルを動かします。
   + NoBom.awkと、NoBom.batを、同じ場所に置きます。
   + 最初に一度、NoBom.batを実行します。inフォルダーとoutフォルダーが出来ます。
   + inフォルダーに、UTF-8で作ったAWKプログラムと入力ファイルを入れます。
   + NoBom.batを実行します。黒い画面が出て、最後に止まります。
   + エラーメッセージが出ていない事を確認して、何かキーを押します。
   + 繰り返し使う時は、inフォルダーや outフォルダーの中を、適当に掃除して下さい。


==
関連ページ:
    ▼AWKの入出力関数とコマンド実行機能▼ABC順
    ▼AWKプログラムを書く▼ABC順
    ▼AWK
    ▼制作メモ
    > getline = ファイル(やパイプ)から1行読み込む
    print = ファイルなどに書き出す
    printf = 文字列を組み立ててファイルなどに書き出す
    +
    GawkでUTF-8のファイルを読み込む時の注意点