0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Ruby で文字列を調べるときのティップス

0
Posted at

Ruby で,特定の文字(や文字列)について

  • バイト表現
  • コードポイント
  • Unicode 名
  • Unicode におけるブロック
  • Unicode における一般カテゴリー

などが知りたいときに使える小技を紹介しよう。

整数を 16 進法の文字列へ

まず準備として,バイト値(0〜255 の整数)やコードポイントの整数を,16 進法の文字列にするやり方について述べる。

0〜255 のバイト値を 2 桁ゼロ埋め大文字 16 進表示の文字列にしたければ,String#% を用いて

p "%02X" % 92 # => "5C"

のようにする。

フォーマット指定の 02 は「ゼロ埋めで 2 桁」を意味する。X は「大文字の 16 進表記」を意味する。小文字がよければ x とする。

バイト列の 16 進表示

文字列のバイト表現は,String#bytes で得られる。

よって,文字列のバイト列を 16 進表示したければ

str = "ほげ"

puts str.bytes.map{ "%02X" % _1 }.join(" ")
# => E3 81 BB E3 81 92

などと書けばよい。

ファイルの先頭 10 バイトがどうなっているか見たければ

head = File.binread("hoge.pdf", 10)
puts head.bytes.map{ "%02X" % _1 }.join(" ")

のようにする。(binread で読み込むこと!)

コードポイント列

Unicode では,コードポイントは U+3042 のように,「U+」に続けて 4〜6 桁の 16 進法で表すことになっている。
数値として 0xFFF 以下であっても 3 桁以下にはせず,ゼロ埋めするルールだ。

文字列のコードポイント列は,String#codepoints で得られる。
返り値は整数の配列である。

よって,文字列のコードポイント列表示は

str = "𩸽1尾"
puts str.codepoints.map{ "U+%04X" % _1 }.join(" ")
# => U+29E3D U+0031 U+5C3E

のようにして得られる。

フォーマット指定について補足すると,04 は「ゼロ埋め 4 桁」なのだが,値が 4 桁で収まらないときは 5 桁以上になってくれる。
だから Unicode のコードポイント表示のルールどおりになる。

Unicode 情報

Unicode 名

「é」という文字(U+00E9)の Unicode 名は,「LATIN SMALL LETTER E WITH ACUTE」となっている。

これは unicode-name という gem を使えば分かる。

require "unicode/name"

puts Unicode::Name.readable("é")
# => LATIN SMALL LETTER E WITH ACUTE

一般カテゴリー

Unicode では,各文字が何らかの「一般カテゴリー(General Category)」に属す。

3(全角数字の 3)や ۳(アラビア文字の 3)などの文字が属す一般カテゴリーは「Decimal_Number」だ。
(人間が見る文字列としてはこのアンダースコアがスペースになっていたりするが,定義上はアンダースコアであるらしい)

一般カテゴリー名には短い形もあって,「Decimal_Number」の場合は「Nd」である。

いわゆる半角スペースと全角スペースの一般カテゴリーはいずれも「Space_Separator」(Zs)だ(括弧内が短い形)。

一般カテゴリー名は正規表現の \p{ } に使えるので,これが簡単に知れるとありがたい。

これも unicode-categories という gem で調べることができる。

require "unicode/categories"

puts Unicode::Categories.category("3", format: :long)
# => Decimal_Number

puts Unicode::Categories.category("3")
# => Nd

スクリプト(用字系)

スクリプト(script)というのは以下のようなもの

  • 「あ」→ 平仮名
  • 「Q」→ ラテン文字
  • 「Я」→ キリル文字
  • 「아」→ ハングル

これも unicode-scripts という gem で調べられる。

require "unicode/scripts"

puts Unicode::Scripts.script("あ")
# => Hiragana

ブロック

Unicode ブロックも unicode-blocks という gem で調べられる。

require "unicode/blocks"

puts Unicode::Blocks.block("A")
# => Basic Latin

puts Unicode::Blocks.block("魚")
# => CJK Unified Ideographs

puts Unicode::Blocks.block("𩸽")
# => CJK Unified Ideographs Extension B

puts Unicode::Blocks.block("あ")
# => Hiragana

上の例で「あ」は「Hiragana」というブロックになっている。
「あ」はスクリプトも「Hiragana」だった。

スクリプトとブロックの違いに注意

さきほどの例のように,スクリプト名とブロック名が一致していることがある。
そのためしばしば混同されてしまう。
気をつけよう。

「㍍」はスクリプトが「Katakana」だが,ブロックは「CJK Compatibility」である。

正規表現の \p{ }(プロパティー名による文字クラス)で片仮名を指定したいとき

  • \p{Katakana}(スクリプトを指定)
  • \p{In_Katakana}(ブロックを指定;ブロック名の前に In_ を付ける)

の違いに注意する必要がある。

Katakana ブロックは U+30A0〜U+30FF の範囲であって,ここには半角片仮名や「ㇰ」といったものは含まれない。

長さ

文字列のバイト長(何バイトからなるか)は String#bytesize で分かる:

# encoding: UTF-8

p "あ".bytesize # => 3
p "𩸽".bytesize # => 4

単に「文字列の長さ」といったときは,「何文字からなるか」という値だ。
これは String#length で分かる:

p "あ".length # => 1
p "𩸽".length # => 1

しかし,この「何文字からなるか」は自明な概念ではない。
String#length はコードポイントの数を返すので,もし一つの文字が複数のコードポイントからなるのであれば,素朴な文字数よりも大きい値になりうる。

たとえば,「ガ」という文字は,Unicode 正規化方式の違いにより,以下の二つの表し方ができる:

  • Unicode 正規化方式 C: U+30AC
  • Unicode 正規化方式 D: U+30AB U+3099

後者の場合,U+30AB(「カ」)と U+3099(合成用濁点)の並びだ。
よって,length で調べた長さはそれぞれ 1, 2 となる。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?