moji 1.5
Sign up to get free protection for your applications and to get access to all the features.
- data/README.txt +1 -0
- data/lib/flag_set_maker.rb +121 -0
- data/lib/moji.rb +597 -0
- metadata +72 -0
data/README.txt
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
See http://gimite.net/gimite/rubymess/moji.html
|
@@ -0,0 +1,121 @@
|
|
1
|
+
require "forwardable"
|
2
|
+
|
3
|
+
|
4
|
+
module FlagSetMaker
|
5
|
+
|
6
|
+
|
7
|
+
class FlagSet
|
8
|
+
|
9
|
+
def initialize(mod, names, zero= nil)
|
10
|
+
@module= mod
|
11
|
+
@flag_names= names.to_a()
|
12
|
+
@zero_name= zero
|
13
|
+
for i in 0...@flag_names.size
|
14
|
+
mod.const_set(@flag_names[i], Flags.new(1 << i, self))
|
15
|
+
end
|
16
|
+
mod.const_set(@zero_name, Flags.new(0, self)) if @zero_name
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_s(v)
|
20
|
+
names= []
|
21
|
+
@flag_names.each_with_index(){ |name, i| names.push(name) if v[i]==1 }
|
22
|
+
if names.empty?()
|
23
|
+
return (@zero_name.to_s() || "0")
|
24
|
+
elsif names.size==1
|
25
|
+
return names[0].to_s()
|
26
|
+
else
|
27
|
+
return "("+names.join("|")+")"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def inspect(v= nil)
|
32
|
+
return v ? format("%p::%s", @module, to_s(v)) : super()
|
33
|
+
end
|
34
|
+
|
35
|
+
def validate(v)
|
36
|
+
return v&((1 << @flag_names.size)-1)
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
class Flags
|
43
|
+
|
44
|
+
extend(Forwardable)
|
45
|
+
|
46
|
+
def initialize(v, fs)
|
47
|
+
@value= fs.validate(v)
|
48
|
+
@flag_set= fs
|
49
|
+
end
|
50
|
+
|
51
|
+
def to_i()
|
52
|
+
return @value
|
53
|
+
end
|
54
|
+
|
55
|
+
def to_s()
|
56
|
+
return @flag_set.to_s(@value)
|
57
|
+
end
|
58
|
+
|
59
|
+
def inspect()
|
60
|
+
return @flag_set.inspect(@value)
|
61
|
+
end
|
62
|
+
|
63
|
+
def ==(rhs)
|
64
|
+
return rhs.is_a?(Flags) && @flag_set==rhs.flag_set && @value==rhs.to_i()
|
65
|
+
end
|
66
|
+
|
67
|
+
alias :eql? :==
|
68
|
+
|
69
|
+
def_delegators(:to_i, :hash)
|
70
|
+
|
71
|
+
def &(rhs)
|
72
|
+
return new_flag(@value&rhs.to_i())
|
73
|
+
end
|
74
|
+
|
75
|
+
def |(rhs)
|
76
|
+
return new_flag(@value|rhs.to_i())
|
77
|
+
end
|
78
|
+
|
79
|
+
def ~()
|
80
|
+
return new_flag(~@value)
|
81
|
+
end
|
82
|
+
|
83
|
+
def include?(flags)
|
84
|
+
return (@value&flags.to_i())==flags.to_i()
|
85
|
+
end
|
86
|
+
|
87
|
+
def empty?()
|
88
|
+
return @value!=0
|
89
|
+
end
|
90
|
+
|
91
|
+
protected
|
92
|
+
|
93
|
+
attr_reader(:flag_set)
|
94
|
+
|
95
|
+
private
|
96
|
+
|
97
|
+
def new_flag(v)
|
98
|
+
return Flags.new(v, @flag_set)
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
102
|
+
|
103
|
+
|
104
|
+
def make_flag_set(*args)
|
105
|
+
FlagSet.new(self, *args)
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
|
110
|
+
|
111
|
+
if __FILE__==$0
|
112
|
+
|
113
|
+
class Hoge
|
114
|
+
|
115
|
+
extend(FlagSetMaker)
|
116
|
+
|
117
|
+
make_flag_set([:FOO, :BAR, :HOGE], :NONE)
|
118
|
+
|
119
|
+
end
|
120
|
+
|
121
|
+
end
|
data/lib/moji.rb
ADDED
@@ -0,0 +1,597 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
#このファイルの文字コードはUTF-8です。
|
4
|
+
#このファイルをUnicode非対応のエディタで編集してはいけません(〜が文字化ける)。
|
5
|
+
|
6
|
+
=begin
|
7
|
+
|
8
|
+
=Moji モジュール
|
9
|
+
|
10
|
+
日本語の文字種判定、文字種変換(半角→全角、ひらがな→カタカナなど)を行います。
|
11
|
+
|
12
|
+
==ダウンロード / インストール:
|
13
|
+
|
14
|
+
((<URL:http://gimite.ddo.jp/pukiwiki/index.php?Ruby%BE%AE%CA%AA%BD%B8>))
|
15
|
+
からダウンロードし、解凍してできた moji ディレクトリの中で以下のコマンドを実行してください。
|
16
|
+
|
17
|
+
# ruby setup.rb
|
18
|
+
|
19
|
+
または、 moji/lib の中の moji.rb と flag_set_maker.rb を lib/ruby/site_ruby/1.8 などにコピーしてください。
|
20
|
+
|
21
|
+
==使い方:
|
22
|
+
|
23
|
+
Ruby 1.8: (({$KCODE})) を指定してから (({require "moji"})) してください。
|
24
|
+
Moji モジュールの関数に渡す文字列の文字コードは (({$KCODE})) と一致させてください。
|
25
|
+
|
26
|
+
Ruby 1.9: どの文字コードの文字列を渡しても大丈夫ですが、 String#encoding が正しく設定されている
|
27
|
+
必要があります。正規表現を返す関数( Moji.kata など)は Encoding.default_internal
|
28
|
+
(設定されてない場合はUTF-8)用の正規表現を返します。その他のエンコーディング用の正規表現は
|
29
|
+
Moji.kata(Encoding::SJIS) などで取得できます。
|
30
|
+
|
31
|
+
$KCODE= "UTF8" # Ruby 1.9では不要
|
32
|
+
require "moji"
|
33
|
+
|
34
|
+
#文字種判定。
|
35
|
+
p Moji.type("漢") # => Moji::ZEN_KANJI
|
36
|
+
p Moji.type?("A", Moji::ZEN) # => true
|
37
|
+
|
38
|
+
#文字種変換。
|
39
|
+
p Moji.zen_to_han("Ruby") # => "Ruby"
|
40
|
+
p Moji.upcase("Ruby") # => "RUBY"
|
41
|
+
p Moji.kata_to_hira("ルビー") # => "るびー"
|
42
|
+
|
43
|
+
#文字種による正規表現。
|
44
|
+
p /#{Moji.kata}+#{Moji.hira}+/ =~ "ぼくドラえもん" # => 6
|
45
|
+
p Regexp.last_match.to_s # => "ドラえもん"
|
46
|
+
|
47
|
+
==定数:
|
48
|
+
|
49
|
+
以下の定数は、文字種の一番細かい分類です。
|
50
|
+
(({Moji.type})) が返すのは、以下の定数のうちの1つです。
|
51
|
+
|
52
|
+
--- HAN_CONTROL
|
53
|
+
制御文字。
|
54
|
+
--- HAN_ASYMBOL
|
55
|
+
ASCIIに含まれる半角記号。
|
56
|
+
--- HAN_JSYMBOL
|
57
|
+
JISに含まれるがASCIIには含まれない半角記号。
|
58
|
+
--- HAN_NUMBER
|
59
|
+
半角数字。
|
60
|
+
--- HAN_UPPER
|
61
|
+
半角アルファベット大文字。
|
62
|
+
--- HAN_LOWER
|
63
|
+
半角アルファベット小文字。
|
64
|
+
--- HAN_KATA
|
65
|
+
半角カタカナ。
|
66
|
+
--- ZEN_ASYMBOL
|
67
|
+
JISの全角記号のうち、ASCIIに対応する半角記号があるもの。
|
68
|
+
--- ZEN_JSYMBOL
|
69
|
+
JISの全角記号のうち、ASCIIに対応する半角記号がないもの。
|
70
|
+
--- ZEN_NUMBER
|
71
|
+
全角数字。
|
72
|
+
--- ZEN_UPPER
|
73
|
+
全角アルファベット大文字。
|
74
|
+
--- ZEN_LOWER
|
75
|
+
全角アルファベット小文字。
|
76
|
+
--- ZEN_HIRA
|
77
|
+
ひらがな。
|
78
|
+
--- ZEN_KATA
|
79
|
+
全角カタカナ。
|
80
|
+
--- ZEN_GREEK
|
81
|
+
ギリシャ文字。
|
82
|
+
--- ZEN_CYRILLIC
|
83
|
+
キリル文字。
|
84
|
+
--- ZEN_LINE
|
85
|
+
罫線のかけら。
|
86
|
+
--- ZEN_KANJI
|
87
|
+
漢字。
|
88
|
+
|
89
|
+
以下の定数は、上の文字種の組み合わせと別名です。
|
90
|
+
|
91
|
+
--- HAN_SYMBOL
|
92
|
+
JISに含まれる半角記号。(({HAN_ASYMBOL | HAN_JSYMBOL}))
|
93
|
+
--- HAN_ALPHA
|
94
|
+
半角アルファベット。(({HAN_UPPER | HAN_LOWER}))
|
95
|
+
--- HAN_ALNUM
|
96
|
+
半角英数字。(({HAN_ALPHA | HAN_NUMBER}))
|
97
|
+
--- HAN
|
98
|
+
全ての半角文字。(({HAN_CONTROL | HAN_SYMBOL | HAN_ALNUM | HAN_KATA}))
|
99
|
+
--- ZEN_SYMBOL
|
100
|
+
JISに含まれる全角記号。(({ZEN_ASYMBOL | ZEN_JSYMBOL}))
|
101
|
+
--- ZEN_ALPHA
|
102
|
+
全角アルファベット。(({ZEN_UPPER | ZEN_LOWER}))
|
103
|
+
--- ZEN_ALNUM
|
104
|
+
全角英数字。(({ZEN_ALPHA | ZEN_NUMBER}))
|
105
|
+
--- ZEN_KANA
|
106
|
+
全角かな/カナ。(({ZEN_KATA | ZEN_HIRA}))
|
107
|
+
--- ZEN
|
108
|
+
JISに含まれる全ての全角文字。(({ZEN_SYMBOL | ZEN_ALNUM | ZEN_KANA | ZEN_GREEK | ZEN_CYRILLIC | ZEN_LINE | ZEN_KANJI}))
|
109
|
+
--- ASYMBOL
|
110
|
+
ASCIIに含まれる半角記号とその全角版。(({HAN_ASYMBOL | ZEN_ASYMBOL}))
|
111
|
+
--- JSYMBOL
|
112
|
+
JISに含まれるが (({ASYMBOL})) には含まれない全角/半角記号。(({HAN_JSYMBOL | ZEN_JSYMBOL}))
|
113
|
+
--- SYMBOL
|
114
|
+
JISに含まれる全ての全角/半角記号。(({HAN_SYMBOL | ZEN_SYMBOL}))
|
115
|
+
--- NUMBER
|
116
|
+
全角/半角数字。(({HAN_NUMBER | ZEN_NUMBER}))
|
117
|
+
--- UPPER
|
118
|
+
全角/半角アルファベット大文字。(({HAN_UPPER | ZEN_UPPER}))
|
119
|
+
--- LOWER
|
120
|
+
全角/半角アルファベット小文字。(({HAN_LOWER | ZEN_LOWER}))
|
121
|
+
--- ALPHA
|
122
|
+
全角/半角アルファベット。(({HAN_ALPHA | ZEN_ALPHA}))
|
123
|
+
--- ALNUM
|
124
|
+
全角/半角英数字。(({HAN_ALNUM | ZEN_ALNUM}))
|
125
|
+
--- HIRA
|
126
|
+
(({ZEN_HIRA})) の別名。
|
127
|
+
--- KATA
|
128
|
+
全角/半角カタカナ。(({HAN_KATA | ZEN_KATA}))
|
129
|
+
--- KANA
|
130
|
+
全角/半角 かな/カナ。(({KATA | ZEN_HIRA}))
|
131
|
+
--- GREEK
|
132
|
+
(({ZEN_GREEK})) の別名。
|
133
|
+
--- CYRILLIC
|
134
|
+
(({ZEN_CYRILLIC})) の別名。
|
135
|
+
--- LINE
|
136
|
+
(({ZEN_LINE})) の別名。
|
137
|
+
--- KANJI
|
138
|
+
(({ZEN_KANJI})) の別名。
|
139
|
+
--- ALL
|
140
|
+
上記全ての文字。
|
141
|
+
|
142
|
+
==モジュール関数:
|
143
|
+
|
144
|
+
--- Moji.type(ch)
|
145
|
+
|
146
|
+
文字 ((|ch|)) の文字種を返します。
|
147
|
+
|
148
|
+
「一番細かい分類」の((<定数|定数:>))のうち1つを返します。
|
149
|
+
|
150
|
+
上の分類に当てはまらない文字(Unicodeのハングルなど)に対しては (({nil})) を返します。
|
151
|
+
また、UnicodeのB面以降の文字に対しても (({nil})) を返します。
|
152
|
+
|
153
|
+
文字が割り当てられていない文字コードに対する結果は不定です( (({nil})) を返す事もあります)。
|
154
|
+
|
155
|
+
p Moji.type("漢") # => Moji::ZEN_KANJI
|
156
|
+
|
157
|
+
--- Moji.type?(ch, type)
|
158
|
+
|
159
|
+
文字 ((|ch|)) が文字種 ((|type|)) に含まれれば、 (({true})) を返します。
|
160
|
+
|
161
|
+
((|type|)) には全ての((<定数|定数:>))と、それらを (({|}))
|
162
|
+
で結んだものを使えます。
|
163
|
+
|
164
|
+
p Moji.type?("A", Moji::ZEN) # => true
|
165
|
+
|
166
|
+
--- Moji.regexp(type[, encoding])
|
167
|
+
|
168
|
+
文字種 ((|type|)) の1文字を表す正規表現を返します。
|
169
|
+
|
170
|
+
((|type|)) には全ての((<定数|定数:>))と、それらを (({|}))
|
171
|
+
で結んだものを使えます。
|
172
|
+
|
173
|
+
Ruby 1.9では ((|encoding|)) に Encoding オブジェクトを渡すと、指定のエンコーディング用の
|
174
|
+
正規表現を返します。
|
175
|
+
省略すると Encoding.default_internal (指定されてない場合は Encoding::UTF_8 )とみなします。
|
176
|
+
|
177
|
+
p Moji.regexp(Moji::HIRA) # => /[ぁ-ん]/
|
178
|
+
|
179
|
+
--- Moji.zen_to_han(str[, type])
|
180
|
+
|
181
|
+
文字列 ((|str|)) の全角を半角に変換して返します。
|
182
|
+
|
183
|
+
((|type|)) には、変換対象とする文字種を((<定数|定数:>))で指定します。
|
184
|
+
デフォルトは (({ALL})) (全て)です。
|
185
|
+
|
186
|
+
p Moji.zen_to_han("Ruby!?") # => "Ruby!?"
|
187
|
+
p Moji.zen_to_han("Ruby!?", Moji::ALPHA) # => "Ruby!?"
|
188
|
+
|
189
|
+
--- Moji.han_to_zen(str[, type])
|
190
|
+
|
191
|
+
文字列 ((|str|)) の半角を全角に変換して返します。
|
192
|
+
|
193
|
+
((|type|)) には、変換対象とする文字種を((<定数|定数:>))で指定します。
|
194
|
+
デフォルトは (({ALL})) (全て)です。
|
195
|
+
|
196
|
+
p Moji.han_to_zen("Ruby!?") # => "Ruby!?"
|
197
|
+
p Moji.han_to_zen("Ruby!?", Moji::SYMBOL) # => "Ruby!?"
|
198
|
+
|
199
|
+
--- Moji.normalize_zen_han(str)
|
200
|
+
|
201
|
+
文字列 ((|str|)) の大文字、小文字を一般的なものに統一します。
|
202
|
+
|
203
|
+
具体的には、ASCIIに含まれる記号と英数字( (({ALNUM|ASYMBOL}))
|
204
|
+
)を半角に、それ以外の記号とカタカナ( (({JSYMBOL|HAN_KATA})) )を全角に変換します。
|
205
|
+
|
206
|
+
--- Moji.upcase(str[, type])
|
207
|
+
|
208
|
+
文字列 ((|str|)) の小文字を大文字に変換して返します。
|
209
|
+
|
210
|
+
((|type|)) には、変換対象とする文字種を((<定数|定数:>))で指定します。
|
211
|
+
デフォルトは (({LOWER})) (全角/半角のアルファベット)です。
|
212
|
+
ギリシャ文字、キリル文字には対応していません。
|
213
|
+
|
214
|
+
p Moji.upcase("Ruby") # => "RUBY"
|
215
|
+
|
216
|
+
--- Moji.downcase(str[, type])
|
217
|
+
|
218
|
+
文字列 ((|str|)) の小文字を大文字に変換して返します。
|
219
|
+
|
220
|
+
((|type|)) には、変換対象とする文字種を((<定数|定数:>))で指定します。
|
221
|
+
デフォルトは (({UPPER})) (全角/半角のアルファベット)です。
|
222
|
+
ギリシャ文字、キリル文字には対応していません。
|
223
|
+
|
224
|
+
p Moji.downcase("Ruby") # => "ruby"
|
225
|
+
|
226
|
+
--- Moji.kata_to_hira(str)
|
227
|
+
|
228
|
+
文字列 ((|str|)) の全角カタカナをひらがなに変換して返します。
|
229
|
+
|
230
|
+
半角カタカナは直接変換できません。 (({han_to_zen})) で全角にしてから変換してください。
|
231
|
+
|
232
|
+
p Moji.kata_to_hira("ルビー") # => "るびー"
|
233
|
+
|
234
|
+
--- Moji.hira_to_kata(str)
|
235
|
+
|
236
|
+
文字列 ((|str|)) のひらがなを全角カタカナに変換して返します。
|
237
|
+
|
238
|
+
p Moji.hira_to_kata("るびー") # => "ルビー"
|
239
|
+
|
240
|
+
--- Moji.han_control([encoding])
|
241
|
+
--- Moji.han_asymbol([encoding])
|
242
|
+
--- ...
|
243
|
+
--- Moji.kana([encoding])
|
244
|
+
--- ...
|
245
|
+
|
246
|
+
((<定数|定数:>))それぞれに対応するメソッドが有り、
|
247
|
+
それぞれの文字種の1文字を表す正規表現を返します。
|
248
|
+
|
249
|
+
例えば、 (({Moji.kana})) は (({Moji.regexp(Moji::KANA)})) と同じです。
|
250
|
+
|
251
|
+
Ruby 1.9では ((|encoding|)) に Encoding オブジェクトを渡すと、指定のエンコーディング用の
|
252
|
+
正規表現を返します。
|
253
|
+
省略すると Encoding.default_internal (指定されてない場合は Encoding::UTF_8 )とみなします。
|
254
|
+
|
255
|
+
以下の例のように、文字クラスっぽく使えます。
|
256
|
+
p /#{Moji.kata}+#{Moji.hira}+/ =~ "ぼくドラえもん" # => 6
|
257
|
+
p Regexp.last_match.to_s # => "ドラえもん"
|
258
|
+
|
259
|
+
==動作環境:
|
260
|
+
|
261
|
+
たぶんRuby 1.8以降。
|
262
|
+
|
263
|
+
Linux Ruby 1.8.7, 1.9.2にて動作確認しました。
|
264
|
+
|
265
|
+
==作者:
|
266
|
+
|
267
|
+
Gimite 市川 (連絡先: ((<URL:http://gimite.ddo.jp/bbs/tnote.cgi>)) )
|
268
|
+
|
269
|
+
==ライセンス:
|
270
|
+
|
271
|
+
Public Domainです。煮るなり焼くなりご自由に。
|
272
|
+
|
273
|
+
==更新履歴:
|
274
|
+
|
275
|
+
2010/9/19 Ver.1.5
|
276
|
+
*Ruby 1.9に対応。
|
277
|
+
|
278
|
+
2008/8/30 Ver.1.4
|
279
|
+
*Moji.type("\n")がnilを返すバグを修正。(thanks to 橋爪さん)
|
280
|
+
|
281
|
+
2006/7/23 Ver.1.3
|
282
|
+
*半角中黒(・)の字種判別、全角中黒との相互変換ができていなかったのを修正。(thanks to xyzzyさん)
|
283
|
+
|
284
|
+
2006/10/5 Ver.1.2
|
285
|
+
*EUC 以外の文字コードにも対応し、ライブラリ名を Moji に変更。
|
286
|
+
*han_to_zen, zen_to_han の対象文字種のデフォルトを全て( (({ALL})) )に。
|
287
|
+
*normalize_zen_han 追加。
|
288
|
+
|
289
|
+
2005/1/3 Ver.1.1
|
290
|
+
*(({$KCODE})) が指定されていないとEUCUtil.typeが正常動作しない問題を修正。
|
291
|
+
*定数に (({ASYMBOL})) と (({JSYMBOL})) を追加。
|
292
|
+
|
293
|
+
2004/11/16 Ver.1.0
|
294
|
+
*EUCUtil 公開。
|
295
|
+
|
296
|
+
=end
|
297
|
+
|
298
|
+
|
299
|
+
if RUBY_VERSION < "1.9.0" && $KCODE=="NONE"
|
300
|
+
warn("Warning: Set $KCODE before requiring 'moji' (UTF8 assumed)")
|
301
|
+
$KCODE= "u"
|
302
|
+
end
|
303
|
+
|
304
|
+
require "enumerator"
|
305
|
+
require "flag_set_maker"
|
306
|
+
if RUBY_VERSION < "1.9.0"
|
307
|
+
require "nkf"
|
308
|
+
require "jcode"
|
309
|
+
end
|
310
|
+
|
311
|
+
nkf_kcode= RUBY_VERSION >= "1.9.0" ? nil : {"SJIS" => "s", "EUC" => "e"}[$KCODE]
|
312
|
+
|
313
|
+
script= <<'EOS'
|
314
|
+
|
315
|
+
|
316
|
+
module Moji
|
317
|
+
|
318
|
+
extend(FlagSetMaker)
|
319
|
+
|
320
|
+
module Detail
|
321
|
+
|
322
|
+
HAN_ASYMBOL_LIST= ' !"#$%&\'()*+,-./:;<=>?@[\]^_`{|}~'
|
323
|
+
ZEN_ASYMBOL_LIST= ' !”#$%&’()*+,-./:;<=>?@[¥]^_‘{|} ̄'
|
324
|
+
HAN_JSYMBOL1_LIST= '。「」、ー゙゚・'
|
325
|
+
ZEN_JSYMBOL1_LIST= '。「」、ー゛゜・'
|
326
|
+
ZEN_JSYMBOL_LIST= '、。・゛゜´`¨ヽヾゝゞ〃仝々〆〇ー―‐\~〜∥…‥“〔〕〈〉《》「」『』【】'+
|
327
|
+
'±×÷≠≦≧∞∴♂♀°′″℃¢£§☆★○●◎◇◇◆□■△▲▽▼※〒→←↑↓〓'
|
328
|
+
HAN_KATA_LIST= 'ハヒフヘホウカキクケコサシスセソタチツテトアイエオナニヌネノマミムメモヤユヨラリルレロワヲンァィゥェォャュョッ'.split(//)
|
329
|
+
HAN_VSYMBOLS= ['', '゙', '゚']
|
330
|
+
ZEN_KATA_LISTS= [
|
331
|
+
'ハヒフヘホウカキクケコサシスセソタチツテトアイエオ'+
|
332
|
+
'ナニヌネノマミムメモヤユヨラリルレロワヲンァィゥェォャュョッ',
|
333
|
+
'バビブベボヴガギグゲゴザジズゼゾダヂヅデド',
|
334
|
+
'パピプペポ',
|
335
|
+
].map(){ |s| s.split(//) }
|
336
|
+
|
337
|
+
if RUBY_VERSION >= "1.9.0"
|
338
|
+
|
339
|
+
def self.convert_encoding(str, &block)
|
340
|
+
orig_enc = str.encoding
|
341
|
+
if orig_enc == Encoding::UTF_8
|
342
|
+
# 無駄なコピーを避けるためにencodeを呼ばない。
|
343
|
+
return yield(str)
|
344
|
+
else
|
345
|
+
result = yield(str.encode(Encoding::UTF_8))
|
346
|
+
return result.is_a?(String) ? result.encode(orig_enc) : result
|
347
|
+
end
|
348
|
+
end
|
349
|
+
|
350
|
+
else
|
351
|
+
|
352
|
+
def self.convert_encoding(str, &block)
|
353
|
+
return yield(str)
|
354
|
+
end
|
355
|
+
|
356
|
+
end
|
357
|
+
|
358
|
+
end
|
359
|
+
|
360
|
+
def self.uni_range(*args)
|
361
|
+
if RUBY_VERSION >= "1.9.0"
|
362
|
+
str= args.each_slice(2).map(){ |f, e| '\u%04x-\u%04x' % [f, e] }.join("")
|
363
|
+
return /[#{str}]/
|
364
|
+
elsif $KCODE=="UTF8"
|
365
|
+
str= args.map(){ |n| NKF.nkf("-wW160x", [n].pack("n")) }.
|
366
|
+
enum_slice(2).map(){ |f, e| "#{f}-#{e}" }.to_s()
|
367
|
+
return /[#{str}]/u
|
368
|
+
else
|
369
|
+
return nil
|
370
|
+
end
|
371
|
+
end
|
372
|
+
|
373
|
+
make_flag_set([
|
374
|
+
:HAN_CONTROL, :HAN_ASYMBOL, :HAN_JSYMBOL, :HAN_NUMBER, :HAN_UPPER, :HAN_LOWER, :HAN_KATA,
|
375
|
+
:ZEN_ASYMBOL, :ZEN_JSYMBOL, :ZEN_NUMBER, :ZEN_UPPER, :ZEN_LOWER, :ZEN_HIRA, :ZEN_KATA,
|
376
|
+
:ZEN_GREEK, :ZEN_CYRILLIC, :ZEN_LINE, :ZEN_KANJI,
|
377
|
+
])
|
378
|
+
|
379
|
+
HAN_SYMBOL= HAN_ASYMBOL | HAN_JSYMBOL
|
380
|
+
HAN_ALPHA= HAN_UPPER | HAN_LOWER
|
381
|
+
HAN_ALNUM= HAN_ALPHA | HAN_NUMBER
|
382
|
+
HAN= HAN_CONTROL | HAN_SYMBOL | HAN_ALNUM | HAN_KATA
|
383
|
+
ZEN_SYMBOL= ZEN_ASYMBOL | ZEN_JSYMBOL
|
384
|
+
ZEN_ALPHA= ZEN_UPPER | ZEN_LOWER
|
385
|
+
ZEN_ALNUM= ZEN_ALPHA | ZEN_NUMBER
|
386
|
+
ZEN_KANA= ZEN_KATA | ZEN_HIRA
|
387
|
+
ZEN= ZEN_SYMBOL | ZEN_ALNUM | ZEN_KANA | ZEN_GREEK | ZEN_CYRILLIC | ZEN_LINE | ZEN_KANJI
|
388
|
+
ASYMBOL= HAN_ASYMBOL | ZEN_ASYMBOL
|
389
|
+
JSYMBOL= HAN_JSYMBOL | ZEN_JSYMBOL
|
390
|
+
SYMBOL= HAN_SYMBOL | ZEN_SYMBOL
|
391
|
+
NUMBER= HAN_NUMBER | ZEN_NUMBER
|
392
|
+
UPPER= HAN_UPPER | ZEN_UPPER
|
393
|
+
LOWER= HAN_LOWER | ZEN_LOWER
|
394
|
+
ALPHA= HAN_ALPHA | ZEN_ALPHA
|
395
|
+
ALNUM= HAN_ALNUM | ZEN_ALNUM
|
396
|
+
HIRA= ZEN_HIRA
|
397
|
+
KATA= HAN_KATA | ZEN_KATA
|
398
|
+
KANA= KATA | ZEN_HIRA
|
399
|
+
GREEK= ZEN_GREEK
|
400
|
+
CYRILLIC= ZEN_CYRILLIC
|
401
|
+
LINE= ZEN_LINE
|
402
|
+
KANJI= ZEN_KANJI
|
403
|
+
ALL= HAN | ZEN
|
404
|
+
|
405
|
+
CHAR_REGEXPS= {
|
406
|
+
HAN_CONTROL => /[\x00-\x1f\x7f]/,
|
407
|
+
HAN_ASYMBOL =>
|
408
|
+
Regexp.new("["+Detail::HAN_ASYMBOL_LIST.gsub(/[\[\]\-\^\\]/){ "\\"+$& }+"]"),
|
409
|
+
HAN_JSYMBOL => Regexp.new("["+Detail::HAN_JSYMBOL1_LIST+"]"),
|
410
|
+
HAN_NUMBER => /[0-9]/,
|
411
|
+
HAN_UPPER => /[A-Z]/,
|
412
|
+
HAN_LOWER => /[a-z]/,
|
413
|
+
HAN_KATA => /[ヲ-ッア-ン]/,
|
414
|
+
ZEN_ASYMBOL => Regexp.new("["+Detail::ZEN_ASYMBOL_LIST+"]"),
|
415
|
+
ZEN_JSYMBOL => Regexp.new("["+Detail::ZEN_JSYMBOL_LIST+"]"),
|
416
|
+
ZEN_NUMBER => /[0-9]/,
|
417
|
+
ZEN_UPPER => /[A-Z]/,
|
418
|
+
ZEN_LOWER => /[a-z]/,
|
419
|
+
ZEN_HIRA => /[ぁ-ん]/,
|
420
|
+
ZEN_KATA => /[ァ-ヶ]/,
|
421
|
+
ZEN_GREEK => /[Α-Ωα-ω]/,
|
422
|
+
ZEN_CYRILLIC => /[А-Яа-я]/,
|
423
|
+
ZEN_LINE => uni_range(0x2570, 0x25ff) || /[─-╂]/,
|
424
|
+
ZEN_KANJI => uni_range(0x3400, 0x4dbf, 0x4e00, 0x9fff, 0xf900, 0xfaff) || /[亜-瑤]/,
|
425
|
+
}
|
426
|
+
|
427
|
+
def type(ch)
|
428
|
+
Detail.convert_encoding(ch) do |ch|
|
429
|
+
ch= ch.slice(/\A./m)
|
430
|
+
result = nil
|
431
|
+
for tp, reg in CHAR_REGEXPS
|
432
|
+
if ch=~reg
|
433
|
+
result= tp
|
434
|
+
break
|
435
|
+
end
|
436
|
+
end
|
437
|
+
result
|
438
|
+
end
|
439
|
+
end
|
440
|
+
|
441
|
+
def type?(ch, tp)
|
442
|
+
Detail.convert_encoding(ch) do |ch|
|
443
|
+
tp.include?(type(ch))
|
444
|
+
end
|
445
|
+
end
|
446
|
+
|
447
|
+
def regexp(tp, encoding= nil)
|
448
|
+
|
449
|
+
regs= []
|
450
|
+
for tp2, reg in CHAR_REGEXPS
|
451
|
+
regs.push(reg) if tp.include?(tp2)
|
452
|
+
end
|
453
|
+
reg= regs.size==1 ? regs[0] : Regexp.new(regs.join("|"))
|
454
|
+
|
455
|
+
if RUBY_VERSION >= "1.9.0" && !encoding
|
456
|
+
encoding= Encoding.default_internal || Encoding::UTF_8
|
457
|
+
end
|
458
|
+
if encoding && encoding != Encoding::UTF_8
|
459
|
+
return Regexp.new(reg.to_s().encode(encoding))
|
460
|
+
else
|
461
|
+
return reg
|
462
|
+
end
|
463
|
+
|
464
|
+
end
|
465
|
+
|
466
|
+
def zen_to_han(str, tp= ALL)
|
467
|
+
Detail.convert_encoding(str) do |str|
|
468
|
+
if tp.include?(ZEN_KATA)
|
469
|
+
reg= Regexp.new("["+Detail::ZEN_KATA_LISTS.to_s()+"]")
|
470
|
+
str= str.gsub(reg) do
|
471
|
+
for i in 0...3
|
472
|
+
pos= Detail::ZEN_KATA_LISTS[i].index($&)
|
473
|
+
break Detail::HAN_KATA_LIST[pos]+Detail::HAN_VSYMBOLS[i] if pos
|
474
|
+
end
|
475
|
+
end
|
476
|
+
end
|
477
|
+
str= str.tr("a-z", "a-z") if tp.include?(ZEN_LOWER)
|
478
|
+
str= str.tr("A-Z", "A-Z") if tp.include?(ZEN_UPPER)
|
479
|
+
str= str.tr("0-9", "0-9") if tp.include?(ZEN_NUMBER)
|
480
|
+
str= str.tr(Detail::ZEN_ASYMBOL_LIST,
|
481
|
+
Detail::HAN_ASYMBOL_LIST.gsub(/[\-\^\\]/){ "\\"+$& }) if tp.include?(ZEN_ASYMBOL)
|
482
|
+
str= str.tr(Detail::ZEN_JSYMBOL1_LIST,
|
483
|
+
Detail::HAN_JSYMBOL1_LIST) if tp.include?(ZEN_JSYMBOL)
|
484
|
+
str
|
485
|
+
end
|
486
|
+
end
|
487
|
+
|
488
|
+
def han_to_zen(str, tp= ALL)
|
489
|
+
Detail.convert_encoding(str) do |str|
|
490
|
+
#[半]濁音記号がJSYMBOLに含まれるので、KATAの変換をJSYMBOLより前にやる必要あり。
|
491
|
+
if tp.include?(HAN_KATA)
|
492
|
+
str= str.gsub(/(#{han_kata})([゙゚]?)/) do
|
493
|
+
i= {""=>0, "゙"=>1, "゚"=>2}[$2]
|
494
|
+
pos= Detail::HAN_KATA_LIST.index($1)
|
495
|
+
s= Detail::ZEN_KATA_LISTS[i][pos]
|
496
|
+
(!s || s=="") ? Detail::ZEN_KATA_LISTS[0][pos]+$2 : s
|
497
|
+
end
|
498
|
+
end
|
499
|
+
str= str.tr("a-z", "a-z") if tp.include?(HAN_LOWER)
|
500
|
+
str= str.tr("A-Z", "A-Z") if tp.include?(HAN_UPPER)
|
501
|
+
str= str.tr("0-9", "0-9") if tp.include?(HAN_NUMBER)
|
502
|
+
str= str.tr(Detail::HAN_ASYMBOL_LIST.gsub(/[\-\^\\]/){ "\\"+$& },
|
503
|
+
Detail::ZEN_ASYMBOL_LIST) if tp.include?(HAN_ASYMBOL)
|
504
|
+
str= str.tr(Detail::HAN_JSYMBOL1_LIST,
|
505
|
+
Detail::ZEN_JSYMBOL1_LIST) if tp.include?(HAN_JSYMBOL)
|
506
|
+
str
|
507
|
+
end
|
508
|
+
end
|
509
|
+
|
510
|
+
def normalize_zen_han(str)
|
511
|
+
Detail.convert_encoding(str) do |str|
|
512
|
+
zen_to_han(han_to_zen(str, HAN_JSYMBOL|HAN_KATA), ZEN_ALNUM|ZEN_ASYMBOL)
|
513
|
+
end
|
514
|
+
end
|
515
|
+
|
516
|
+
def upcase(str, tp= LOWER)
|
517
|
+
Detail.convert_encoding(str) do |str|
|
518
|
+
str= str.tr("a-z", "A-Z") if tp.include?(HAN_LOWER)
|
519
|
+
str= str.tr("a-z", "A-Z") if tp.include?(ZEN_LOWER)
|
520
|
+
str
|
521
|
+
end
|
522
|
+
end
|
523
|
+
|
524
|
+
def downcase(str, tp= UPPER)
|
525
|
+
Detail.convert_encoding(str) do |str|
|
526
|
+
str= str.tr("A-Z", "a-z") if tp.include?(HAN_UPPER)
|
527
|
+
str= str.tr("A-Z", "a-z") if tp.include?(ZEN_UPPER)
|
528
|
+
str
|
529
|
+
end
|
530
|
+
end
|
531
|
+
|
532
|
+
def kata_to_hira(str)
|
533
|
+
Detail.convert_encoding(str) do |str|
|
534
|
+
str.tr("ァ-ン", "ぁ-ん")
|
535
|
+
end
|
536
|
+
end
|
537
|
+
|
538
|
+
def hira_to_kata(str)
|
539
|
+
Detail.convert_encoding(str) do |str|
|
540
|
+
str.tr("ぁ-ん", "ァ-ン")
|
541
|
+
end
|
542
|
+
end
|
543
|
+
|
544
|
+
module_function(
|
545
|
+
:type, :type?, :regexp, :zen_to_han, :han_to_zen, :normalize_zen_han, :upcase, :downcase,
|
546
|
+
:kata_to_hira, :hira_to_kata
|
547
|
+
)
|
548
|
+
|
549
|
+
def self.define_regexp_method(name, tp)
|
550
|
+
define_method(name) do |*args|
|
551
|
+
regexp(tp, *args)
|
552
|
+
end
|
553
|
+
module_function(name)
|
554
|
+
end
|
555
|
+
|
556
|
+
#han_control, han_asymbol, …などのモジュール関数を定義。
|
557
|
+
for cons in constants
|
558
|
+
val= const_get(cons)
|
559
|
+
define_regexp_method(cons.downcase(), val) if val.is_a?(FlagSetMaker::Flags)
|
560
|
+
end
|
561
|
+
|
562
|
+
def self.test()
|
563
|
+
orig_str= "ドラえもん(Doraemon)は、日本で1番有名な漫画だ。"
|
564
|
+
for encoding in RUBY_VERSION >= "1.9.0" ? [Encoding::UTF_8, Encoding::SJIS] : [nil]
|
565
|
+
str= encoding ? orig_str.encode(encoding) : orig_str
|
566
|
+
str.each_char() do |ch|
|
567
|
+
ch= ch.encode(Encoding::UTF_8) if encoding
|
568
|
+
printf("%2s %s\n", ch, Moji.type(ch))
|
569
|
+
end
|
570
|
+
str= Moji.zen_to_han(str, Moji::ALL)
|
571
|
+
if encoding
|
572
|
+
puts(str.encode(Encoding::UTF_8))
|
573
|
+
puts(str.encoding)
|
574
|
+
else
|
575
|
+
puts(str)
|
576
|
+
end
|
577
|
+
str= Moji.han_to_zen(str, Moji::ALL)
|
578
|
+
if encoding
|
579
|
+
puts(str.encode(Encoding::UTF_8))
|
580
|
+
puts(str.encoding)
|
581
|
+
else
|
582
|
+
puts(str)
|
583
|
+
end
|
584
|
+
end
|
585
|
+
end
|
586
|
+
|
587
|
+
end
|
588
|
+
|
589
|
+
EOS
|
590
|
+
|
591
|
+
script= NKF.nkf("-#{nkf_kcode}Wx", script) if nkf_kcode
|
592
|
+
#UTF-8の場合、nkfしてはいけない(~が〜になるので)。
|
593
|
+
eval(script, TOPLEVEL_BINDING)
|
594
|
+
|
595
|
+
if __FILE__==$0
|
596
|
+
Moji.test()
|
597
|
+
end
|
metadata
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: moji
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 5
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 1
|
8
|
+
- 5
|
9
|
+
version: "1.5"
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Hiroshi Ichikawa
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-09-20 00:00:00 +09:00
|
18
|
+
default_executable:
|
19
|
+
dependencies: []
|
20
|
+
|
21
|
+
description: Character type classification/conversion for Japanese
|
22
|
+
email: gimite+moji@gmail.com
|
23
|
+
executables: []
|
24
|
+
|
25
|
+
extensions: []
|
26
|
+
|
27
|
+
extra_rdoc_files: []
|
28
|
+
|
29
|
+
files:
|
30
|
+
- README.txt
|
31
|
+
- lib/moji.rb
|
32
|
+
- lib/flag_set_maker.rb
|
33
|
+
has_rdoc: true
|
34
|
+
homepage: http://gimite.net/gimite/rubymess/moji.html
|
35
|
+
licenses: []
|
36
|
+
|
37
|
+
post_install_message:
|
38
|
+
rdoc_options:
|
39
|
+
- --quiet
|
40
|
+
- --title
|
41
|
+
- moji Reference
|
42
|
+
- --main
|
43
|
+
- lib/moji.rb
|
44
|
+
require_paths:
|
45
|
+
- lib
|
46
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
47
|
+
none: false
|
48
|
+
requirements:
|
49
|
+
- - ">="
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
hash: 3
|
52
|
+
segments:
|
53
|
+
- 0
|
54
|
+
version: "0"
|
55
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
56
|
+
none: false
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
hash: 3
|
61
|
+
segments:
|
62
|
+
- 0
|
63
|
+
version: "0"
|
64
|
+
requirements: []
|
65
|
+
|
66
|
+
rubyforge_project:
|
67
|
+
rubygems_version: 1.3.7
|
68
|
+
signing_key:
|
69
|
+
specification_version: 3
|
70
|
+
summary: Character type classification/conversion for Japanese
|
71
|
+
test_files: []
|
72
|
+
|