« 2011年6月 | トップページ | 2011年10月 »

2011年7月

2011年7月21日 (木)

vimでURL Unescape(utf-8)

Webサーバーのログをvimで見ていて、このエスケープされた値ってなんだろうと気になった
時にすぐに調べられる関数をvimscriptで作った。
下記のスクリプトを.vimrcに張り付けるなどして、set encoding?がutf-8の状態で
:call Unescape()を実行すると、カーソルのある行をutf-8でURL Unescapeした文字列が
echoされる。

function GetCode(pos,str)
  let s:pos = a:pos
  let s:n_code = str2nr(strpart(a:str,s:pos,2),16)
  let s:pos = s:pos + 2
  "in a certain sns
  "if s:n_code == 37
  "  let s:n_code = str2nr(strpart(s:line,s:pos,2),16)
  "  let s:pos = s:pos + 2
  "endif
  return [s:pos,s:n_code]
endfunction

function Unescape()
  let s:line = getline(".")
  let s:out = ""
  let s:pos = 0
  while s:pos < strlen(s:line)
    let s:moji =strpart(s:line,s:pos,1)
    let s:pos = s:pos + 1
    if s:moji == "%"
      let s:rc = GetCode(s:pos,s:line)
      let s:pos = s:rc[0]
      let s:f_code = s:rc[1]
      if s:f_code >= 0xe0
        "disregard %
        let s:pos = s:pos + 1
        let s:rc = GetCode(s:pos,s:line)
        let s:pos = s:rc[0]
        let s:s_code = s:rc[1]
        "disregard %
        let s:pos = s:pos + 1
        let s:rc = GetCode(s:pos,s:line)
        let s:pos = s:rc[0]
        let s:t_code = s:rc[1]
        let s:out = s:out . nr2char(float2nr((s:f_code - 0xe0) * pow(2,12) + (s:s_code - 0x80) * pow(2,6) + (s:t_code - 0x80)))
      else
        if s:n_code >= 0xc0
          "disregard %
          let s:pos = s:pos + 1
          let s:rc = GetCode(s:pos,s:line)
          let s:pos = s:rc[0]
          let s:s_code = s:rc[1]
          let s:out = s:out . nr2char(float2nr((s:f_code - 0xc0) * pow(2,6) + (s:s_code - 0x80)))
        else
          let s:out = s:out . nr2char(s:n_code)
        endif
      endif
    else
      let s:out = s:out . s:moji
    endif
  endwhile
  echo s:out
endfunction

補足

'あ'のunicodeは0x3042なのにURL Escapeすると0xe3,0x81,0x82になるのはなんでだろうと 思っていたのだが、Unicodeは各文字ごとのコードのことを表し、utf-8とはそのコードをバイト として表現する(符号化)ことらしい。
どういうことかというと、utf-8の場合、最初のバイトの先頭4bitを使って、表そうとしている
文字が何バイト使っているかを表し、1100だと2バイト、1110だと3バイトとなる。
0x3042は16bit使うので、3バイトのグループ に入り、先頭4bitが1110となる。 そして、0x3042を2進数で表すと 0011000001000010となるのだが、そのうち先頭4bitを先ほどの 1100にくっつけるので、先頭バイトは11100011となる。
2バイト目はマルチバイトを表すため、先頭のbitの1を立て、さきほどの4bit後の6bitを下位6bitにくっつける ので、10000001となる。
3バイト目も同様にマルチバイトを表すため、先頭のbitの1を立て、16bitのうちの残りの6bitを下位6bitに くっつければ、10000010となる。
これが、0x3042のユニコードがutf-8だと3バイト0x3e(11100011),0x81(10000001),0x82(10000010) となる理由。

| | コメント (0) | トラックバック (0)

« 2011年6月 | トップページ | 2011年10月 »