[総集編] Pythonで日本語の正規表現チェックをする

実務で厳密に日本語のチェックをする必要があり、かなり苦労したので、 **まじめ** にまとめた。

対象：

- ひらがな
- カタカナ
- ｶﾀｶﾅ    ←曲者
- 漢字    ←超曲者

ついでに、以下も扱います。　　　

- 数字 (１２３, 123)
- 英字 (ＡＢＣ, ａｂｃ, ABC, abc)

## まとめ

まずは、まとめです。この後詳細にそれぞれ検証していきます。

| 種類               | 対象の文字列                                                                                                                                                                     | 正規表現                                 | 備考・コメント                                                   | 
| :----------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------- | :--------------------------------------------------------------- | 
| ひらがな           | ぁあぃいぅうぇえぉおかがきぎくぐけげこごさざしじすずせぜそぞただちぢっつづてでとどなにぬねのはばぱひびぴふぶぷへべぺほぼぽまみむめもゃやゅゆょよらりるれろゎわゐゑをんゔゕゖ | [ぁ-ゖ]                                  | ゕ, ゖを含まない場合：[ぁ-ゔ]                                    | 
| カタカナ(全角)     | ァアィイゥウェエォオカガキギクグケゲコゴサザシジスズセゼソゾタダチヂッツヅテデトドナニヌネノハバパヒビピフブプヘベペホボポマミムメモャヤュユョヨラリルレロヮワヰヱヲンヴヵヶ | [ァ-ヶ]                                  | ヵ, ヶを含まない場合：[ァ-ヴ]<br>ヷヸヹヺを含めたい場合：[ァ-ヺ] | 
| ｶﾀｶﾅ (半角)    | ｦｧｨｩｪｫｬｭｮｯｰｱｲｳｴｵｶｷｸｹｺｻｼｽｾｿﾀﾁﾂﾃﾄﾅﾆﾇﾈﾉﾊﾋﾌﾍﾎﾏﾐﾑﾒﾓﾔﾕﾖﾗﾘﾙﾚﾛﾜﾝﾞﾟ                                                             | [ｦ-ﾟ]                                  | [ｦ-ﾝ] は濁点系の文字が除外されるので注意<br>(ｼﾞ, ﾋﾟ 等)      | 
| 漢字(第〇水準漢字) | 一丁... 齢龍　(計: 2965文字)<br>※第1水準の場合                                                                                                                                  | [一丁・・・略(全ての漢字)・・・齢龍]<br> | ダサい場合は、unicodeの正規表現                                  | 
| 半角英字           | ABCDEFGHIJKLMNOPQRSTUVWXYZ<br>abcdefghijklmnopqrstuvwxyz                                                                                                                             | [A-Za-z]                                 |                                                                  | 
| 全角英字           | ＡＢＣＤＥＦＧＨＩＪＫＬＭＮＯＰＱＲＳＴＵＶＷＸＹＺ<br>ａｂｃｄｅｆｇｈｉｊｋｌｍｎｏｐｑｒｓｔｕｖｗｘｙｚ                                                                         | [Ａ-Ｚａ-ｚ]                             |                                                                  | 
| 半角数字           | 0123456789                                                                                                                                                                       | [0-9]                                    |                                                                  | 
| 全角数字<br>       | ０１２３４５６７８９                                                                                                                                                             | [０-９]                                  |                                                                  | 


## ひらがな
```txt
対象文字列：
ぁあぃいぅうぇえぉおかがきぎくぐけげこごさざしじすずせぜそぞただちぢっつづてでとどなにぬねの
はばぱひびぴふぶぷへべぺほぼぽまみむめもゃやゅゆょよらりるれろゎわゐゑをんゔゕゖ
```

調べるとよく書かれているパターンは以下である。
ただし、これだと一部の文字が含まれない。
`[ぁ-ん]`

```py
p = re.compile('^[ぁ-ん]+$')

print(p.fullmatch('ぁ') is not None)     # => True
print(p.fullmatch('ょ') is not None)     # => True
print(p.fullmatch('あ') is not None)     # => True
print(p.fullmatch('ぷ') is not None)     # => True
print(p.fullmatch('を') is not None)     # => True
print(p.fullmatch('ん') is not None)     # => True

print(p.fullmatch('ゔ') is not None)    # => False                   
print(p.fullmatch('ゕ') is not None)    # => False                   
print(p.fullmatch('ゖ') is not None)    # => False                   
```

ゔ、ゕ、ゖ　が Flaseになってしまう。
なので、`[ぁ-ゖ]` のほうが望ましい。


```py
p = re.compile('^[ぁ-ゖ]+$')

print(p.fullmatch('ぁ') is not None)     # => True
print(p.fullmatch('ょ') is not None)     # => True
print(p.fullmatch('あ') is not None)     # => True
print(p.fullmatch('ぷ') is not None)     # => True
print(p.fullmatch('を') is not None)     # => True
print(p.fullmatch('ん') is not None)     # => True

print(p.fullmatch('ゔ') is not None)    # => True                   
print(p.fullmatch('ゕ') is not None)    # => True                   
print(p.fullmatch('ゖ') is not None)    # => True                   
```

全てTrueになった。

ただし、
小さい`「か」` `「け」` の使いみちがよくわからないので、
意図的に無くすのであれば、`[ぁ-ゔ]`がベターなのかもしれない。


## カタカナ (全角)
```txt
対象文字列：
ァアィイゥウェエォオカガキギクグケゲコゴサザシジスズセゼソゾタダチヂッツヅテデトドナニヌネノ
ハバパヒビピフブプヘベペホボポマミムメモャヤュユョヨラリルレロヮワヰヱヲンヴヵヶヷヸヹヺ
```
カタカナもひらがなと同じく、`[ァ-ン]`ではなく、`[ァ-ヶ]`が良い。
`ヷヸヹヺ` は使っているところを見たことないので今回は不要とした。
(こういうものは必要になったときに足すで良いと判断)


```py
p = re.compile('^[ァ-ヶ]+$')

print(p.fullmatch('ァ') is not None)     # => True
print(p.fullmatch('ョ') is not None)     # => True
print(p.fullmatch('ア') is not None)     # => True
print(p.fullmatch('ジ') is not None)     # => True
print(p.fullmatch('ヲ') is not None)     # => True
print(p.fullmatch('ン') is not None)     # => True

print(p.fullmatch('ヴ') is not None)    # => True                   
print(p.fullmatch('ヵ') is not None)    # => True                   
print(p.fullmatch('ヶ') is not None)    # => True              
```

## ｶﾀｶﾅ (半角)
```txt
対象文字列；
ｦｧｨｩｪｫｬｭｮｯｰｱｲｳｴｵｶｷｸｹｺｻｼｽｾｿﾀﾁﾂﾃﾄﾅﾆﾇﾈﾉﾊﾋﾌﾍﾎﾏﾐﾑﾒﾓﾔﾕﾖﾗﾘﾙﾚﾛﾜﾝﾞﾟ
```
半角カタカナは少し特殊である。
よく見るのは以下である。
`[ｦ-ﾝ]`

実はこれだと、濁点、半濁音符が合致しません。

```py
p = re.compile('^[ｦ-ﾝ]+$')

print(p.fullmatch('ｱ') is not None)     # => True
print(p.fullmatch('ｮ') is not None)     # => True
print(p.fullmatch('ｱ') is not None)     # => True
print(p.fullmatch('ｼ') is not None)     # => True
print(p.fullmatch('ｦ') is not None)     # => True

print(p.fullmatch('ｼﾞ') is not None)    # => False
print(p.fullmatch('ﾋﾟ') is not None)    # => False

```

半角の場合は濁点系は1文字とされているので、以下のように個別に指定をする必要がある。
`[ｦ-ﾟ]`

```py
p = re.compile('^[ｦ-ﾟ]+$')

print(p.fullmatch('ｱ') is not None)     # => True
print(p.fullmatch('ｮ') is not None)     # => True
print(p.fullmatch('ｱ') is not None)     # => True
print(p.fullmatch('ｼ') is not None)     # => True
print(p.fullmatch('ｦ') is not None)     # => True

print(p.fullmatch('ｼﾞ') is not None)   # => True
print(p.fullmatch('ﾋﾟ') is not None)   # => True   
```


## 漢字
### 第〇〇水準漢字について
今回は第1水準と第2水準漢字を判別する方法。
第3、第4はフォントが対応してない場合があるので印刷系の場合は除いておくのがベターである。

第1、第2水準漢字がそもそも何か知りたい場合は以下のサイトがかなりわかりやすい。(オススメ)
そもそもを知りたい場合：

https://blog.natade.net/2018/11/18/shift_jis-cp932-jis%E6%BC%A2%E5%AD%97%E6%B0%B4%E6%BA%96/

どんな漢字が属しているか知りたい場合：
[第1水準漢字](http://www13.plala.or.jp/bigdata/jis_1.html), [第2水準漢字](http://www13.plala.or.jp/bigdata/jis_2.html), [第3水準漢字](http://www13.plala.or.jp/bigdata/jis_3.html),  [第4水準漢字](http://www13.plala.or.jp/bigdata/jis_4.html)

### sjift-jisは第1,2水準漢字にしか対応していない!
shift-jisは第1,2水準漢字にのみ対応している
ちなみに、第1~4に対応しているのは、shift_jisx0213である。

よって、sjisでencodeして正規表現チェックするのは得策ではない。
なぜなら、第3以降の漢字や、sjisに対応していない文字が含まれた場合、
**UnicodeEncodeError**になってしまうためである。

```py
# 第三水準漢字(㐂)をshift-jisでエンコード
print("㐂".encode('shift-jis'))    # エンコードできない
# UnicodeEncodeError: 'shift_jis' codec can't encode character '\u3402' in position 0: illegal multibyte sequence

# 第三水準漢字(㐂)をshift_jisx0213でエンコード
print("㐂".encode('shift_jisx0213'))   # => b'\x87\xa1'   　エンコード可能

# 例えば、㈳ はshift_jisx0213でもエンコードできない
print("㈳".encode('shift_jisx0213'))   # エンコードできない
# UnicodeEncodeError: 'shift_jisx0213' codec can't encode character '\u3233' in position 0: illegal multibyte sequence

```
※ shift_jisx0213は第3以降の漢字にも対応するが、万能ではない


### 第1水準漢字をチェックする方法 ダメだったパターン集
#### ダメなパターン①　: **[亜-腕]**

一番目にするパターンかもしれない。

```
p = re.compile('^[亜-腕]+$')

print(p.fullmatch('亜') is not None) # => True 
print(p.fullmatch('和') is not None) # => True
print(p.fullmatch('腕') is not None) # => True

print(p.fullmatch('丸') is not None) # => False
print(p.fullmatch('互') is not None) # => False
```


これはpythonで正規表現チェックする場合はunicode順でみるので、正しくない。
unicode順に出力してみるとよく分かる。(スクショでごめんなさい)
**互**などは亜の前にある。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/182994/757bcd64-bc39-2c7d-221b-4b729d1b04a8.png)


#### ダメなパターン②　: **[一-龍]**

2番目に目にするパターン
一見良さげだが、第２~4の漢字も含まれてしまう。
これは、漢字をunicode順にすると第1~4までがきれいにソートされているわけではないからである。

```py
p = re.compile('^[一-龍]+$')

print(p.fullmatch('亜') is not None) # => True 
print(p.fullmatch('和') is not None) # => True
print(p.fullmatch('腕') is not None) # => True

print(p.fullmatch('丸') is not None) # => True
print(p.fullmatch('互') is not None) # => True

print(p.fullmatch('弌') is not None) # => True      第2水準の漢字
print(p.fullmatch('氵') is not None) # => True      第4水準の漢字
```

#### ダメではないが、避けたパターン③　: shift-jisにencodeして正規表現

shift-jisで正規表現チェックする場合
以下方法で可能のようだが、前述したとおり、shift-jisに対応していないコードが入り込んできた場合、
**UnicodeEncodeError**が発生する為やめた。

あと、個人的にはこの正規表現が本当にあっているのか、可読性と検証のしにくさの点で避けた。

```py
# 第1水準漢字（16 - 47 区）にマッチ
regexp_for_JIS_16_TO_47 = re.compile(r'\x88[\x9F-\xFC]|[\x89-\x97][\x40-\xFC]|\x98[\x40-\x9E]')

# SJIS にエンコードしてマッチング
regexp_for_JIS_16_TO_47.match(u"腕".encode('sjis'))

```

引用元

https://weblog.ymt2.net/blog/html/2013/11/11/regular_expression_for_jis_x_0208.html


##### ダメではないが、避けたパターン④　: unicodeで正規表現
理由は、`ダメではないが、避けたパターン③`とほぼ同じで、可読性という点と、
その正規表現を作れる自身がなかったのでやめた。(コスパが悪そう)


###　第1水準漢字をチェックする方法 最終的な方法
結論第一水準をリストで管理するのが、ミスもなく実装に対するコスパがいいと判断した。
正直ダサいきもするが。。。安心感もある。

```py
# 第1水準の漢字 (亜-腕)
FIRST_KANJI=\
'一丁七万丈三上下不与丑且世丘丙丞両並中串丸丹主乃久之乍乎乏乗乙九乞也乱乳乾亀了予争事二云互五井亘亙些亜亡交亥亦亨享京亭亮人什仁仇今介仏仔仕他付仙代令以仮仰仲件任企伊伍伎伏伐休会伝伯伴伶伸伺似伽佃但位低'\
'住佐佑体何余作佳併佼使侃例侍供依侠価侭侮侯侵侶便係促俄俊俗保信俣修俳俵俸俺倉個倍倒倖候借倣値倦倫倭倶倹偉偏停健偲側偵偶偽傍傑傘備催傭債傷傾僅働像僑僕僚僧僻儀億儒償優儲允元兄充兆兇先光克免兎児党兜入全八'\
'公六共兵其具典兼内円冊再冒冗写冠冥冨冬冴冶冷凄准凋凌凍凝凡処凧凪凱凶凸凹出函刀刃分切刈刊刑列初判別利到制刷券刺刻剃則削前剖剛剣剤剥副剰割創劃劇劉力功加劣助努劫励労効劾勃勅勇勉動勘務勝募勢勤勧勲勺勾勿匁'\
'匂包化北匙匝匠匡匪匹区医匿十千升午半卑卒卓協南単博卜占卦卯印危即却卵卸卿厄厘厚原厨厩厭厳去参又叉及友双反収叔取受叙叛叡叢口古句叩只叫召可台叱史右叶号司吃各合吉吊吋同名后吏吐向君吟吠否含吸吹吻吾呂呆呈呉'\
'告呑周呪味呼命咋和咲咳咽哀品哉員哨哩哲唄唆唇唐唖唯唱唾啄商問啓善喉喋喚喜喝喧喪喫喬喰営嗣嘆嘉嘗嘘嘩嘱噂噌噛器噴噸噺嚇嚢囚四回因団困囲図固国圃圏園土圧在圭地坂均坊坐坑坤坦坪垂型垢垣埋城埜域埠埴執培基埼堀'\
'堂堅堆堕堤堪堰報場堵堺塀塁塊塑塔塗塘塙塚塞塩填塵塾境墓増墜墨墳墾壁壇壊壌壕士壬壮声壱売壷変夏夕外夙多夜夢大天太夫央失夷奄奇奈奉奏契奔套奥奨奪奮女奴好如妃妄妊妓妖妙妥妨妬妹妻妾姉始姐姑姓委姥姦姪姫姶姻姿'\
'威娃娘娠娩娯娼婁婆婚婦婿媒媛嫁嫉嫌嫡嬉嬢嬬嬰子孔字存孜孝孟季孤学孫宅宇守安宋完宍宏宕宗官宙定宛宜宝実客宣室宥宮宰害宴宵家容宿寂寄寅密富寒寓寛寝察寡寧審寮寵寸寺対寿封専射将尉尊尋導小少尖尚尤尭就尺尻尼尽'\
'尾尿局居屈届屋屍屑展属屠屡層履屯山岐岡岨岩岬岱岳岸峠峡峨峯峰島峻崇崎崖崩嵐嵩嵯嶋嶺巌川州巡巣工左巧巨差己巳巴巷巻巽巾市布帆希帖帝帥師席帯帰帳常帽幅幌幕幡幣干平年幸幹幻幼幽幾庁広庄庇床序底庖店庚府度座庫'\
'庭庵庶康庸廃廉廊廓廟廠延廷建廻廼廿弁弄弊式弐弓弔引弗弘弛弟弥弦弧弱張強弼弾彊当形彦彩彪彫彬彰影役彼往征径待律後徐徒従得御復循微徳徴徹徽心必忌忍志忘忙応忠快念忽怒怖怜思怠急性怨怪怯恋恐恒恕恢恥恨恩恭息恰'\
'恵悉悌悔悟悠患悦悩悪悲悶悼情惇惑惚惜惟惣惨惰想惹愁愈愉意愚愛感慈態慌慎慕慢慣慧慨慮慰慶慾憂憎憐憤憧憩憲憶憾懇懐懲懸戊戎成我戒或戚戟戦戯戴戸戻房所扇扉手才打払托扮扱扶批承技抄把抑投抗折抜択披抱抵抹押抽担'\
'拍拐拒拓拘拙招拝拠拡括拭拳拶拷拾持指按挑挙挟挨挫振挺挽挿捉捌捕捗捜捧捨据捲捷捺捻掃授掌排掘掛掠採探接控推掩措掬掲掴掻揃描提揖揚換握揮援揺損搬搭携搾摂摘摩摸摺撃撒撚撞撤撫播撮撰撲撹擁操擢擦擬擾支改攻放政'\
'故敏救敗教敢散敦敬数整敵敷文斉斌斎斐斑斗料斜斡斤斥斧斬断斯新方於施旅旋族旗既日旦旧旨早旬旭旺昂昆昇昌明昏易昔星映春昧昨昭是昼時晃晋晒晦晩普景晴晶智暁暇暑暖暗暢暦暫暮暴曇曙曜曝曲曳更書曹曽曾替最月有朋服'\
'朔朕朗望朝期木未末本札朱朴机朽杉李杏材村杓杖杜束条杢来杭杯東杵杷松板枇析枕林枚果枝枠枢枯架柁柄柊柏某柑染柔柘柚柱柳柴柵査柾柿栂栃栄栓栖栗校栢株栴核根格栽桁桂桃案桐桑桓桔桜桝桟桧桶梁梅梓梗梢梧梨梯械梱梶'\
'梼棄棉棋棒棚棟森棲棺椀椅椋植椎椙椛検椴椿楊楓楕楚楠楢業楯楳極楼楽概榊榎榔榛構槌槍様槙槻槽樋樗標樟模権横樫樵樹樺樽橋橘機橡橿檀檎櫓櫛櫨欄欝欠次欣欧欲欺欽款歌歎歓止正此武歩歪歯歳歴死殆殉殊残殖殴段殺殻殿毅'\
'母毎毒比毘毛氏民気水氷永氾汀汁求汎汐汗汚汝江池汰汲決汽沃沈沌沓沖沙没沢沫河沸油治沼沿況泉泊泌法泡波泣泥注泰泳洋洗洛洞津洩洪洲活派流浄浅浜浦浩浪浬浮浴海浸消涌涙涛涜涯液涼淀淋淑淘淡淫深淳淵混添清渇済渉渋'\
'渓渚減渠渡渥渦温測港湊湖湘湛湧湯湾湿満溌源準溜溝溢溶溺滅滋滑滝滞滴漁漂漆漉漏演漕漠漢漣漫漬漸潅潔潜潟潤潮潰澄澗澱激濁濃濠濡濫濯瀕瀞瀦瀧瀬灘火灯灰灸灼災炉炊炎炭点為烈烏烹焔焚無焦然焼煉煎煙煤照煩煮煽熊熔'\
'熟熱燃燈燐燕燥燦燭爆爪爵父爺爽爾片版牌牒牙牛牝牟牡牢牧物牲特牽犀犠犬犯状狂狐狗狙狛狩独狭狸狼狽猛猟猪猫献猶猷猿獄獅獣獲玄率玉王玖玩玲珂珊珍珠珪班現球理琉琢琳琴琵琶瑚瑛瑞瑠瑳璃環璽瓜瓢瓦瓶甑甘甚甜生産甥'\
'用甫田由甲申男町画界畏畑畔留畜畝畠畢略畦番異畳畷畿疋疎疏疑疫疲疹疾病症痔痕痘痛痢痩痴療癌癒癖発登白百的皆皇皐皮皿盃盆盈益盗盛盟監盤目盲直相盾省眉看県真眠眺眼着睡督睦瞥瞬瞭瞳矛矢知矧矩短矯石砂研砕砥砦砧'\
'砲破砺砿硝硫硬硯硲碁碇碍碑碓碕碗碧碩確磁磐磨磯礁礎示礼社祁祇祈祉祐祖祝神祢祥票祭祷禁禄禅禍禎福禦禰禽禾禿秀私秋科秒秘租秤秦秩称移稀程税稔稗稚稜種稲稼稽稿穀穂穆積穎穏穐穣穫穴究空穿突窃窄窒窓窟窪窮窯窺竃'\
'立竜章竣童竪端競竹竺竿笈笑笛笠笥符第笹筆筈等筋筏筑筒答策箆箇箔箕算管箪箭箱箸節範篇築篠篤篭簡簸簾簿籍米籾粁粂粉粋粍粒粕粗粘粛粟粥粧精糊糎糖糞糟糠糧糸系糾紀約紅紋納紐純紗紘紙級紛素紡索紫紬累細紳紹紺終絃'\
'組経結絞絡絢給統絵絶絹継続綜綬維綱網綴綻綾綿緊緋総緑緒線締編緩緬緯練縁縄縛縞縦縫縮績繁繊繋繍織繕繭繰纂纏缶罪罫置罰署罵罷羅羊美群羨義羽翁翌習翠翫翰翻翼耀老考者而耐耕耗耳耶耽聖聞聡聯聴職聾肇肉肋肌肖肘肝'\
'股肢肥肩肪肯肱育肴肺胃胆背胎胞胡胤胴胸能脂脅脆脇脈脊脚脱脳脹腎腐腔腕腫腰腸腹腺腿膏膚膜膝膨膳膿臆臓臣臥臨自臭至致臼興舌舎舗舘舛舜舞舟航般舵舶舷船艇艦艮良色艶芋芙芝芥芦芭芯花芳芸芹芽苅苑苓苔苗苛若苦苧苫'\
'英茂茄茅茎茜茨茶茸草荊荏荒荘荷荻莞莫莱菅菊菌菓菖菜菟菩華菰菱萄萌萎萩萱落葉葎著葛葡董葦葬葱葵葺蒋蒐蒔蒙蒜蒲蒸蒼蓄蓉蓋蓑蓬蓮蔀蔑蔓蔚蔦蔭蔵蔽蕃蕉蕊蕎蕗蕨蕩蕪薄薗薙薦薩薪薫薬薮薯藁藍藤藩藷藻蘇蘭虎虐虚虜虞'\
'虫虹虻蚊蚕蚤蛇蛋蛍蛎蛙蛤蛭蛮蛸蛾蜂蜘蜜蝉蝋蝕蝦蝶蝿融螺蟹蟻血衆行術街衛衝衡衣表衰衷衿袈袋袖被袴袷裁裂装裏裕補裟裡裳裸製裾複褐褒襖襟襲西要覆覇見規視覗覚覧親観角解触言訂計訊討訓託記訟訣訪設許訳訴診註証詐'\
'詑詔評詞詠詣試詩詫詮詰話該詳誇誉誌認誓誕誘語誠誤説読誰課誹誼調談請諌諏諒論諜諦諭諮諸諺諾謀謁謂謄謎謙講謝謡謬謹識譜警議譲護讃讐谷豆豊豚象豪豹貌貝貞負財貢貧貨販貫責貯貰貴買貸費貼貿賀賂賃賄資賊賎賑賓賛賜'\
'賞賠賢賦質賭購贈贋赤赦赫走赴起超越趣趨足距跡跨路跳践踊踏蹄蹟蹴躍身躯車軌軍軒軟転軸軽較載輔輝輩輪輯輸輿轄轍轟轡辛辞辰辱農辺辻込辿迂迄迅迎近返迦迩迫迭述迷追退送逃逆透逐逓途逗這通逝速造逢連逮週進逸逼遁遂'\
'遅遇遊運遍過道達違遜遠遡遣遥適遭遮遵遷選遺遼避還邑那邦邪邸郁郊郎郡部郭郵郷都鄭酉酋酌配酎酒酔酢酪酬酵酷酸醇醍醐醒醗醜醤醸釆采釈里重野量金釘釜針釣釦釧鈍鈎鈴鈷鉄鉛鉢鉦鉱鉾銀銃銅銑銘銚銭鋒鋤鋪鋭鋲鋳鋸鋼錆'\
'錐錘錠錦錨錫錬錯録鍋鍍鍔鍛鍬鍵鍾鎌鎖鎗鎚鎧鎮鏑鏡鐘鐙鐸鑑鑓長門閃閉開閏閑間関閣閤閥閲闇闘阜阪防阻阿陀附降限陛院陣除陥陪陰陳陵陶陸険陽隅隆隈隊階随隔隙際障隠隣隷隻隼雀雁雄雅集雇雌雑雛離難雨雪雫雰雲零雷電'\
'需震霊霜霞霧露青靖静非面革靭靴鞄鞍鞘鞠鞭韓韮音韻響頁頂頃項順須預頑頒頓頗領頚頬頭頴頻頼題額顎顔顕願顛類顧風飛食飢飯飲飴飼飽飾餅養餌餐餓館饗首香馨馬馳馴駁駄駅駆駈駐駒駕駿騎騒験騨騰驚骨骸髄高髪髭鬼魁魂魅'\
'魔魚魯鮎鮒鮪鮫鮭鮮鯉鯖鯛鯨鯵鰍鰐鰭鰯鰹鰻鱈鱒鱗鳥鳩鳳鳴鳶鴇鴎鴛鴨鴫鴬鴻鵜鵠鵡鵬鶏鶴鷲鷹鷺鹸鹿麓麗麟麦麹麺麻麿黄黍黒黙黛鼎鼓鼠鼻齢龍'


p = re.compile(f'^[{FIRST_KANJI}]+$')

print(p.fullmatch('亜') is not None) # => True 
print(p.fullmatch('和') is not None) # => True
print(p.fullmatch('腕') is not None) # => True

print(p.fullmatch('丸') is not None) # => True
print(p.fullmatch('互') is not None) # => True

print(p.fullmatch('弌') is not None) # => False      第2水準の漢字
print(p.fullmatch('氵') is not None) # => False      第4水準の漢字
```

以下サイトで、第1,2,3,4の漢字をワンラインでまとめてくれている。

https://www.pre-practice.net/2018/03/jis14_2.html


## 英字
おまけなので簡単に
### 半角英字
```py
p = re.compile('^[Ａ-Ｚａ-ｚ]+$')

# 全角小文字
print(p.fullmatch('a') is not None)    # => Flase
print(p.fullmatch('d') is not None)    # => Flase
print(p.fullmatch('z') is not None)    # => Flase

# 全角大文字
print(p.fullmatch('A') is not None)    # => Flase
print(p.fullmatch('G') is not None)    # => Flase
print(p.fullmatch('Z') is not None)    # => Flase

# 半角小文字
print(p.fullmatch('a') is not None)    # => True
print(p.fullmatch('ｘ') is not None)    # => True
print(p.fullmatch('ｚ') is not None)    # => True

# 半角大文字
print(p.fullmatch('Ａ') is not None)    # => True
print(p.fullmatch('Ｇ') is not None)    # => True
print(p.fullmatch('Ｚ') is not None)    # => True


```

### 全角英字
```py
p = re.compile('^[A-Za-z]+$')

# 全角小文字
print(p.fullmatch('a') is not None)    # => True
print(p.fullmatch('d') is not None)    # => True
print(p.fullmatch('z') is not None)    # => True

# 全角大文字
print(p.fullmatch('A') is not None)    # => True
print(p.fullmatch('G') is not None)    # => True
print(p.fullmatch('Z') is not None)    # => True

# 半角小文字
print(p.fullmatch('ａ') is not None)    # => Flase
print(p.fullmatch('ｘ') is not None)    # => Flase
print(p.fullmatch('ｚ') is not None)    # => Flase

# 半角大文字
print(p.fullmatch('Ａ') is not None)    # => Flase
print(p.fullmatch('Ｇ') is not None)    # => Flase
print(p.fullmatch('Ｚ') is not None)    # => Flase
```


## 数字
おまけなので簡単に

### 半角数字
```PY
p = re.compile('^[0-9]+$')

# 半角
print(p.fullmatch('0') is not None)    # => True
print(p.fullmatch('1') is not None)    # => True
print(p.fullmatch('9') is not None)    # => True
# 全角
print(p.fullmatch('０') is not None)    # => False
print(p.fullmatch('１') is not None)    # => False
print(p.fullmatch('９') is not None)    # => False
```

### 全角数字
```PY
p = re.compile('^[０-９]+$')

# 半角
print(p.fullmatch('0') is not None)    # => False
print(p.fullmatch('1') is not None)    # => False
print(p.fullmatch('9') is not None)    # => False

# 全角
print(p.fullmatch('０') is not None)    # => True
print(p.fullmatch('１') is not None)    # => True
print(p.fullmatch('９') is not None)    # => True

```

## 最後に
例えば英数字、かな、カナ、ｶﾅ、第1水準漢字、第二水準漢字をチェックする場合

```py
# 第1水準の漢字 (亜-腕)
FIRST_KANJI='一丁七万.......鼠鼻齢龍'
# 第２水準の漢字 (弌-熙)
SECOND_KANJI='丐丕丗个......乕乖乘龠'

p = re.compile(f'[0-9０-９A-Za-zＡ-Ｚａ-ｚぁ-ヶァ-ヶｦ-ﾟ{FIRST_KANJI}{SECOND_KANJI}')
```



いい感じにまとまってる記事がないので書いてみました。
最後までありがとうございました。
ミス、ご指摘あればぜひお願いいたします。
お役にたてば幸いです。