日本で働くみんなに優しい人名データベースの作り方

## 結論

姓・名・ミドルネームは別けて管理しよう
日本人名に関してはカナ表記・英字表記のルールを決めよう
文字数制限は長めに設定しておいた方が無難
表記揺れは避けられないのでそもそもが許容できる設計にしよう
通称や旧姓など本名とは異なる名前を管理して適用できる仕組みを持てると優しい
Unicode使おうぜ
ちゃんと正規化しようぜ


## はじめに

人のマスタを作ろうとした時、管理対象が日本人だけであれば難しいことは考えず、直感を信じた設計でも何ら問題のないデータベースを作ることができることは想像に容易い。
しかし、そこに異なる文化圏の外国人が含まれる場合はどうだろうか？

近年では日本で働く外国人の方が増え、名前の表現方法の多様化、通称、日本人でも旧姓で働きたいと思う方も多いと思う。

主にはバックオフィスや社内システムを設計する方向けに、どんな点が考慮されていると「みんなに優しいデータベースが作れるのか。」について「名前」という視点から経験や苦労してきた点、想像の範疇から考察した内容やノウハウを書いてみる。

Webサービスなどにも適用できる話だと思うし、思うけども…。そもそも海外で暮らしたことも実際にバックオフィスにいたこともないので想像の範囲で。。

また、気になる点や「こういうのはどうでしょう？」、「うちではこうしてます！」みたいなのはコメントくれると喜びます。「これは違うと思います！」とかも勉強になります。


## 名前とは

名前はその所有者たる本人だけでなく、その国の文化や法律、姓をつけたご先祖さま、名付け親の考えや想い、バックオフィスとしては人事労務、総務、情シスの正義など様々な要素が絡み合って成り立ってると思う。

自分の名前を気に入ってる方もいれば、大して愛着のない方もいると思うし、日本語では発音しにくいから通称で呼んでほしい、結婚をしたが旧姓を名乗りたい場合など従業員視点での名前というものがある。

また、人事労務の正義では本名の漢字氏名と読み仮名だけあれば人事マスタとして成立するが、情シス的には英字表記の氏名がないと困るなんてケースもありうる。

通称や旧姓などは、度を越していない限りは本人の希望に沿えた方がハッピーだと思うし、なるべくなら色んな正義を持つ方たちが幅広く使えるデータベース = マスタがたった一つあることが夢ドリーム理想郷でみんなハッピーハッピーなのである(暴論)

本音、システム屋として目を覆いたくなるような人事マスタはもう見たくないのである！！
(ワオ。Excelショクニン…テニュウリョク…。)
(ジンジマスタテキナモノ…イッパイアル…。)


## どっちが姓でどっちが名？

人名の構造として多くの文化では、「家の名前(以下:姓)」と「個人の名前(以下:名)」 の組み合わせから構成される

表現方法としては2つある

- 「姓 名」
- 「名 姓」

「太郎 山田」 という人名を目にした時、姓が「山田」で名が「太郎」であることは、長く日本に暮らしている方にしてみれば明白であると思う。

「山田 太郎」 をヘボン式ローマ字で表記しようとすると、 「TARO YAMADA」 もしくは 「YAMADA TARO」 のいずれかとなり、姓が 「YAMADA」 で名が 「TARO」 であることも直感的に理解できる。

「SAKURA AOI」 はどうだろうか？  「姓 名」 の順であるだろうか？ 「名 姓」 の順であるだろうか？
佐倉さんとも青井さんとも受け取れる場合の判別は第三者には容易なことではない。
無論 `"SAKURA AOI"` という文字列を受け取ったシステムが判別を行うことは不可能に近い。

「氏名を入力してください」というフィールドがあった時、少なくとも日本含む東アジア圏では「姓 名」の順番で入力されることだろう。

英語圏に目を向けるとどうだろうか？
「given name + family name」 更にはミドルネームが入力されることもあるだろう。

入力フィールドは姓(family name)と名(given name)でそれぞれを用意し、データベース上も別けて管理することを推奨する。


### ミドルネームやセカンドネームについて

英語圏などミドルネームを使用する文化もあるが、日本では馴染みの薄いミドルネームやセカンドネーム。そもそも法律で認められていない。
「ケンブリッジ・飛鳥・アントニオ」など、日本でミドルネームを使用する場合は名の一部として組み込まれる。

おそらく人事労務的な観点では名の一部として組み込む形で何ら問題はないと想像するが、システム化するにあたっては別に取得したいケースもあるかと思う。

また、ミドルネームやセカンドネームが複数ある場合がある。

「クリスティアーノ・ロナウド」 の本名は、 「クリスティアーノ・ロナウド・ドス・サントス・アヴェイロ」 であり、以下の要素から構成され、表記の順番も英語圏とは異なる。

ファーストネーム: クリスティアーノ
セカンドネーム: ロナウド
母親の姓: ドス・サントス
父親の姓: アヴェイロ


ミドルネーム・セカンドネームについてはなかなかベストプラクティスが思いつかないが、少なくともデータベース上は姓、名とは別に全体をスペース区切りで管理し、表現方法や表記に関しては、表示側で対応するのが望ましい。

| 姓 | 名 | ミドルネーム |
|:-|:-|:-|
| 山田 | 太郎 | NULL |
| ケネディ | ジョン | フィッツジェラルド |
| ロナウド | クリスティアーノ | ドス サントス アヴェイロ |


また入力フィールドを設ける場合は「姓」、「名」とは独立した「ミドルネーム」フィールドがあることが望ましい。


## 本名

本名に関しては上の章で殆ど述べたが、データベースのフィールドとしては以下の9種類を用意しておけば大抵のことは何とかなると思う。

- 本名\_姓
- 本名\_名
- 本名\_ミドル
- 本名\_カナ\_セイ
- 本名\_カナ\_メイ
- 本名\_カナ\_ミドル
- 本名\_英字\_SEI
- 本名\_英字\_MEI
- 本名\_英字\_MID

日本人名の場合、 「本名\_姓」 は `"山田"` 、 「本名\_名」 は `"太郎"` となる
本名\_カナ\_xx には、カナ文字(後述)
本名\_英字\_xx には、ヘボン式ローマ字表記の英字(後述) が挿入される想定

外国人名の場合、 「本名\_姓」、 「本名\_名」、 「本名\_ミドル」 には、日本国政府に対し公的に届け出ている氏名が挿入される想定である
(ミドルネームが名に組み込まれる場合は「本名\_ミドル」は`NULL`とし、「本名\_名」として取り扱い、カナ、英字のミドルネームも同様に取り扱う)
(正直よくわからん...)

以上は人事労務的な正義となる気がするが、通称や旧姓を希望する場合や(希望があれば)異字体の吸収などシステム構築的な観点では「通称」のようなフィールドが別にあると人事労務の正義と競合せず、扱いやすいのではないかと思う。

- 通称\_姓
- 通称\_名
- 通称\_ミドル
- 通称\_カナ\_セイ
- 通称\_カナ\_メイ
- 通称\_カナ\_ミドル
- 通称\_英字\_SEI
- 通称\_英字\_MEI
- 通称\_英字\_MID


## カナ表記

外国籍を持つ方などで綴りは同じでも読み仮名が異なるケースがある

例えば 「Van」 さんのケースでは 「ヴァン」 という表記や 「バン」 という表記がありうるし、
「Alexander」 のケースでも 「アレ**ク**サンダー」、 「アレ**キ**サンダー」 といった表記の揺れは起きうる。
(公的に届け出ている名前であれば表記の揺れと言うのは正しくないのだろうが、システム屋的には悩ましい表記の揺れなのである…。)

「Michael」など由来や綴りは同じでも言語によって大きく読み仮名が変わる(「ミカエル, マイケル, ミシェル, ミハエル」)ケースなどデータベース化するにあたり、正規化が難しく、検索性を下げる要因でもある。

`ヴァ` を `バ` と正規化してから検索するなどは簡単に思いつく実装例だが、 「アレク」 と 「アレキ」 を単純な実装で両方ヒットさせるのは、文字の一致率([ハミング距離](https://ja.wikipedia.org/wiki/%E3%83%8F%E3%83%9F%E3%83%B3%E3%82%B0%E8%B7%9D%E9%9B%A2)や[レーベンシュタイン距離](https://ja.wikipedia.org/wiki/%E3%83%AC%E3%83%BC%E3%83%99%E3%83%B3%E3%82%B7%E3%83%A5%E3%82%BF%E3%82%A4%E3%83%B3%E8%B7%9D%E9%9B%A2))を測るか辞書を使うかくらいしか思いつかず、単純な実装で同一の文字列とみなし検索性を上げるのは難しく感じる。

全文検索エンジンとか使ったらうまくいくのかな？わからん。(よくわからないけど使ったことのないすごそうなものはドラえもんに見える不思議。(大抵大したことない))

正直、ここに関してはノーアイディアであるが、少なくともピュアピュアな気持ちで「ヤマグチ」さんを「ヤマク゛チ」と表記するのだけは避けてほしい。

宣伝: 直前の仮名と結合させる方法についても記事にしているのでよろしければご覧ください。
[[Python] 結合文字を使用した濁点や半濁点を直前の仮名と結合させる方法(ウ゛→ ヴ)](https://qiita.com/syamamura/items/13c0825282415e2e360d)



## 英字表記

英字表記を各種システムアカウントで使用するといったことはよくある事例だと思う。
よくある社内での使用例としてはメールアドレスやActive Directoryのユーザ名などである。

日本人名を英字表記する場合、公的証明書であるパスポートに倣い、 **ヘボン式ローマ字** を採用するのが一般的かと思う。
本人が入力する場合などはパスポートに書いてある内容をそのまま入力するケースもあるかと思う。

しかし、ヘボン式ローマ字の綴り方は 「**パスポートを発行する都道府県によって若干異なるのである**」(白目)

「そんなん計算機に生成させりゃいいじゃん」はごもっともな意見だが、Web変換サービスや公開されているライブラリ間でも変換結果に揺らぎがあった。
3000名(読み仮名の重複あり)のテストデータを用意し、いくつかのライブラリで変換をかけ比較したところ、 基準となる結果から 2〜10% 程の乖離があった。

例えば 「おおの」 の出力例としては以下のようなものがあった

- `ONO` - 最も正しい
- `OHNO` - 都道府県によっては積極的に推奨されない

(流石にOONOと出力するライブラリはなかった)

UUやOUの長音は最も揺らぎが多く、「ゆうこ」の場合は `YUKO`, `YUUKO` 。 「ようこ」 の場合 `YOKO`, `YOUKO` といった結果が6:4程となった。
その他、末尾 「おお」 の場合の例外などの実装はまちまちであった。

同じ言語で作られたシステムであればライブラリの流用は可能であろうが、いくら計算機といえどあっちこっちでいろんなルールで変換してたらそれこそまさにカオス状態である。
ADではルールA, G SuiteではルールB、互換性…ありません！！！ とかなるとどこかのシステム屋がすごく困るんだと思う。

これに対する解決策として日本人名の場合、「カナ文字」からの英字生成ルールを定め、入社時など1つのシステムで生成し、生成されたものは大事にデータベースで管理し、情シスの正義で AD や G Suite などをマスタとした逆流入を発生させないことである。
**マスタが存在する限り常にデータは一方向に流れるべきなのである**

あとは「サンシャイン池崎」を、「SUNSHINE IKEZAKI」 と表記するか 「SANSHAIN IKEZAKI」 と表記するのかどちらが正しいのだろうか…。
恐らく前者であるが、こちらもルール作りの範疇かと思う。

外国人名の場合、パスポートや在留カード記載の表記をそのまま使用するので問題ないかと思う。


### パスポートのルールについての言い訳

パスポートのヘボン式ルールが具体的に都道府県でどこが違ったかは思い出せないのだが、[東京都のルール](https://www.seikatubunka.metro.tokyo.lg.jp/passport/documents/0000000485.html)に準拠したカナ文字からヘボン式ローマ字を生成するライブラリを実際に作ってみて、生成された英字表記と既存のWebサービスやライブラリの生成結果との差分を検証したところかなりの差分が出た。そもそものバグや考慮不足もあったが、東京都のルールではセーフだが兵庫県のルールではアウトみたいな事例も数件あった。
東京都のルールは割と緩く、他都道府県のルールと都合よくマージしてルールを作った。


## 文字数制限について

「佐々木 蔵之介」 など日本人名で6文字あるとかなり長いと感じるが、法的には文字数制限は存在しないらしい。
しかし、そもそもが英字・カナ表記であったり、ミドルネームやセカンドネームまで含めた外国人名は結構長くなることが予想される。

日本人基準で最大文字数を10文字とか15文字に設定してしまうと利用者からクレームの嵐となりそうだし、システム的に文字数制限をかけた結果生成されたアカウント名が重複して障害が発生したなんてことになったら目も当てられないので、少なくともデータベース側では無制限ないし長め (255 Bytes くらい) に設定しておくと良いと思う。
UI側は当然バリデーションを入れること！

システム的な制約としては、メールアドレスのローカル部の最大長 `64 Octets` [^rfc5321] なので、アカウント名生成ルール自体は 64 Octets の制約を受けそうである。
[^rfc5321]: [RFC5321 - 4.5.3.1.1.  Local-part](https://datatracker.ietf.org/doc/html/rfc5321#section-4.5.3.1.1)


## 意外と難しいぞ漢字圏

中国は勿論のこと、韓国、北朝鮮、台湾、ベトナムなどの漢字を使用する(していた)国や地域で使用される人名は日本人名とも高い親和性がある。

マルチバイトの世界でも Chinese, Japanese, Korean の頭文字から `CJK` ( Vietnamese を加えた `CJKV` ) と呼ばれ幅を利かせており、 Unicode でも `CJK統合漢字` (U+4E00..U+9FFF) や `CJK互換漢字` として符号化用集合が収録されている。[^StandardizedVariants]
[^StandardizedVariants]: [StandardizedVariants.txt](https://www.unicode.org/Public/UNIDATA/StandardizedVariants.txt)


文化・言語・文字としても、符号化方式・文字集合としても互換性があるが故に妙にややこしいのである…。

システム化におけるややこしさの一つに、 `JIS X 0208` との互換性の無さが挙げられる。
今時データベースに `Shift_JIS` や `EUC` を使用するケースはないと思われるが、実用上の地味な問題としてフォントがない点と他システムとの連携に不備が生じる可能性がある点である。(日本人名における異体字(「タカハシ」の「高」と「髙」)と大きくは変わらない気はするが…。)

中国語の例では、ピンイン表記(日本語で言うローマ字表記)があり、これが実際の中国語の音とは違うというから「カナ表記」と「英字表記」での乖離が発生する。

中国人名、韓国人名ではパッと見人の目で日本人名と区別がつかず、事務処理が漏れてしまうといった可能性もあるので、システム化する上ではヒューマンエラーが起きないようフォローしたい部分でもある。

ベトナムなど姓のパターンが少ないまたは偏っている国や地域の集団では、名前が衝突する可能性が上昇する([鳩の巣原理](https://ja.wikipedia.org/wiki/%E9%B3%A9%E3%81%AE%E5%B7%A3%E5%8E%9F%E7%90%86))。 当たり前だが同姓同名を許容する設計とし、例えば社員番号の表示や顔写真を検索できるたり、間違いなく個人を識別できる仕組みがあると良い。


## 正規化について

入力された文字列は**可逆的に変換できる範囲**で正規化を行った上でデータベースに格納されることが望ましい。

例として以下大文字小文字混在の入力はデータベース上小文字の `"alexander"` に変換されて格納されているなど。

- `"Alexander"`
- `"alexander"`
- `"ALEXANDER"`

### 可逆的な正規化と不可逆的な正規化


[可逆的](https://dictionary.goo.ne.jp/word/%E5%8F%AF%E9%80%86/)な正規化は、データベース格納時のデータフォーマットの統一を目的に。
[不可逆的](https://dictionary.goo.ne.jp/word/%E4%B8%8D%E5%8F%AF%E9%80%86/)な正規化は、ソート順の最適化や、検索の最適化など、システム的な用途で使用する。


可逆的な正規化の例として、 「(株)ホゲピヨ」 という入力を 「株式会社ホゲピヨ」 とする場合。
この場合は、前株、後株の情報は失われていないので "株式会社" を "(株)" とした上で表示することも "株式会社" と表示することも可能である。

人名の場合、 `alexander` を `Alexander` とすることも `ALEXANDER` ことも容易であるため、可逆的な正規化と言える。


不可逆的な正規化の例として、社名でのソートが直感的となるように 「株式会社ホゲピヨ」 から "株式会社" を取り除いて格納してしまった。
この場合、前株、後株の情報は失われるので、「株式会社ホゲピヨ」であったのか「ホゲピヨ株式会社」であったのかは後から判別することは不可能である。 よって、`search_index_name` といったシステムでしか使わない別フィールドに格納されることが望ましい。

人名の場合、 `高橋`(くちだか) さんや `髙橋`(はしごだか) さん を `高橋`(くちだか) へ統一してしまう正規化は、とあるレコード上の `高橋`(くちだか) さんが本来 `高橋`(くちだか) さんだったのか `髙橋`(はしごだか) さんだったのかわからなくなるため、不可逆的と言える。
用途が検索の最適化などシステム的な都合である限りは、別フィールドに格納されるべきである。


### 英字表記(ASCII文字)

以下の正規化手順を踏んでデータベースへ格納すると良い

1. 全角文字は半角文字へ変換
1. 大文字は小文字へ変換
1. 複数スペースや複数水平タブは1つのスペースへ変換(ミドルネーム用)
    1. `string.replace(input, "[\x20|\t]+", " ")`

バリデーションとしてはシンプルに、こんな正規表現をパスしたらいいと思う。
`^([a-zA-Z]{,255})$`


### 姓名・カナ表記(マルチバイト文字)

以下の正規化手順を踏んでデータベースへ格納すると良い
また、データベースの設定として、 `Unicode` に準じた文字符号化形式を使用することが望ましい (`utf-8` など)


1. (Unicodeの場合) `NFC` へ正規化する (レアケースだが、履歴書のファイル名のコピペ操作などで `NFD` が混ざることがある)
1. 半角カナは全角カナへ変換
1. 単体の濁点、 `゛`、半濁点 `゜` は直前の仮名と統合する
1. 英字表記の正規化手順

バリデーションとしては制御文字や機種依存文字の使用禁止、絵文字の使用禁止など。（当たり前のバリデーションをすればいいと思う)


## 表現方法について

原則的に日本の会社である限りは日本の慣習に従い「姓 名」の順で表記すれば良いと思う
ミドルネームが加わる場合は在留カードのルールに従い「姓 名 ミドル」の順で表記されることが日本人にもわかりやすくて良いと思う
(あとフロントの実装が楽)


## そもそも

公序良俗に反さない範囲かつ原則変更はできないけど本人が責任を持てるのであれば、社内通称やアカウント名は自由に決められる仕組みであれば誰も苦労しないと思う。ホント。


## さいごに

非エンジニアの方にもなんとなく理解できるような内容としたかったが、結局エンジニアのエゴを書き連ねてしまった。。。

DX(笑)も流行ってるしな〜。と思ってテーマに選んでみたものの、子供の頃に散々聞かされた「ユビキタス」と同じ匂いがする。結局ユビキタスの正体はナニでIoTとは何が違ったんだろう。。
ん〜。DX が `Developer eXperience` の略であれば今頃どんな黄金時代を過ごしていたことだろうか……。