mcpField
I
israeli-id-validator

israeli-id-validator

github.com/skills-il開発13168 回インストール3 日前に更新
リポジトリ

israeli-id-validator について

israeli-id-validatorは、イスラエルの個人番号と登録法人番号を検証・処理するスキルです。チェックデジットの規則、安全な入力処理、種別判定の制約を説明し、PythonとJavaScriptの資料を含みます。

主な機能

  1. 01イスラエルIDのチェックデジット検証
  2. 02個人・法人番号の形式ガイド
  3. 03開発テスト用IDの生成
  4. 04一括・マスク対応のPython CLI
  5. 05JavaScript実装リファレンス
  6. 06入力処理とプライバシー保護

活用シーン

  1. 01イスラエルID番号の形式確認
  2. 02ローカル開発テスト用IDの生成
  3. 03ブラウザーやNodeでの検証実装
  4. 04CLIやCI出力での番号マスキング

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/skills-il/developer-tools --skill israeli-id-validator

インストール後、Claude Code で/israeli-id-validatorを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

CHANGELOG.md
evidence.json
metadata.json
optimization-log.json
SKILL_HE.md
references/
id-formats.md
javascript.md
scripts/
validate_id.py

詳細

イスラエルのID検証

手順

ステップ 1:IDの種類を特定する
種類接頭辞桁数例備考
Teudat Zehut(個人ID)なし(推測できません)9桁123456782数字から出生年月日、年齢、居住資格を読み取ることはできません
法人/登記された事業体通常は5で始まります9桁51-530820-3最初の2桁は通常、事業体の種類に関係します(コード50~59、次の表を参照)。これはあくまで可能性の高い分類であり、規則ではありません。個人IDと同じチェックデジットを使用します

法人および登記された事業体のコード(最初の2桁):

接頭辞事業体
50政府系企業、年金/積立基金、または地方委員会
51民間企業(Chevra Ba'am/Ltd)
52公開会社
53委任統治時代のパートナーシップ(Shutafut Mandatorit、イギリス委任統治時代のもの)
54一般パートナーシップ
55パートナーシップ(Shutafut)
56外国企業
57協同組合(Aguda Shitufit)/キブツ
58Amuta(非営利団体)/公益会社
59信託財産(Hekdesh)。法人そのものではありません

接頭辞による種類の判定は経験則です。5で始まる9桁の番号は通常、登記された事業体の番号です(出典によれば、最初の2桁は「通常」事業体の種類に関係し、一覧のコードはすべて5で始まります)。ただし、正式な判定を行えるのは発行機関のみです。接頭辞を理由に番号を拒否したり、どの項目に入力すべきか判断したりしないでください。接頭辞は、ユーザーがすでに会社番号だと述べた番号を分類する目的にのみ使用します。個人のTeudat Zehutは接頭辞から判定できません。

ステップ 2:チェックデジットアルゴリズムで検証する

イスラエルのIDチェックデジットアルゴリズム(すべての種類に適用):

import re


def validate_israeli_id(id_number: str) -> bool:
    """Validate Israeli ID number (TZ, company, amuta, etc.)"""
    # Discard ONLY the separators a human or a spreadsheet legitimately puts
    # inside an ID. Do NOT strip every non-digit: that silently turns
    # "62819482.1" into the VALID id 628194821, and turns "", "abc" and a row
    # of punctuation into "000000000". A validator that accepts garbage is
    # worse than one that rejects a real ID, because nobody finds out.
    # Do NOT gate on str.isdigit() either: it is True for Arabic-Indic digits
    # and superscripts, which either crash int() or validate as another value.
    # For the REASON (empty / malformed / bad check digit) use parse_id() in
    # scripts/validate_id.py; this compact version only answers yes or no.
    if not isinstance(id_number, str):
        return False        # an int has already lost its leading zeros
    # Trim whitespace, a CSV line break, the BOM and LRM/RLM/ALM at the ENDS only.
    # Inside the number a line break or bidi mark stays an error: bidi controls
    # can make the screen show different digits from the ones stored.
    EDGE = " \t\u00a0\r\n\u200b\ufeff\u200e\u200f\u061c"
    SEPARATORS = " -\u2010\u2011\u2013\u2014\u202f\u00a0\u00ad\u200b\u200c\u200d\u2060\ufeff"
    stripped = ''.join(c for c in id_number.strip(EDGE) if c not in SEPARATORS)

    if stripped == '' or not re.fullmatch(r'[0-9]{1,9}', stripped):
        return False        # malformed input, NOT an invalid ID

    id_str = stripped.zfill(9)

    if id_str == '000000000':   # passes Luhn but is never a real ID
        return False

    total = 0
    for i, digit in enumerate(id_str):
        # 1-based odd positions (indices 0,2,4,6,8) multiply by 1
        # 1-based even positions (indices 1,3,5,7) multiply by 2
        weight = 1 if i % 2 == 0 else 2
        val = int(digit) * weight
        if val > 9:
            val = val // 10 + val % 10     # Sum digits if > 9
        total += val

    return total % 10 == 0
ステップ 3:結果を提示する

有効なIDの場合:番号がチェックデジット検査に合格したこと(形式上正しい番号であり、発行済みであることや本人に属することの証明ではありません)を伝え、接頭辞に基づく種類はあくまで可能性の高い分類として提示します 無効なIDの場合:無効であることと、どのチェックに失敗したかを報告し、よくある間違いを示します:

  • 桁の入れ替わり
  • 桁の不足/余分な桁
  • チェックデジットの誤り
ステップ 4:テスト用IDを生成する(開発用途)

開発やテスト用に、有効なテストIDを生成します:

def generate_test_id(prefix: str = "") -> str:
    """Generate a valid Israeli ID number for testing."""
    import random, re
    if not re.fullmatch(r'[0-9]{0,8}', prefix):
        raise ValueError("prefix must be 0-8 ASCII digits")   # else an 11-digit "ID"
    if prefix == '00000000':
        raise ValueError("an all-zeros prefix can only yield 000000000")
    while True:
        base = prefix + ''.join(str(random.randint(0, 9)) for _ in range(8 - len(prefix)))
        if base != '00000000':      # would yield 000000000, which validation rejects
            break
    # Calculate check digit
    total = 0
    for i, digit in enumerate(base):
        weight = 1 if i % 2 == 0 else 2
        val = int(digit) * weight
        if val > 9:
            val = val // 10 + val % 10
        total += val
    check = (10 - (total % 10)) % 10
    return base + str(check)

注意:生成したIDはテスト専用です。実際の本人確認にランダムなIDを使用しないでください。チェックデジットに合格する生成番号が、実在する人物に発行されたIDである可能性はあります。ジェネレーターにはそれを判別する方法がないため、生成した番号が人や第三者の目に触れるものに含まれないようにしてください(「注意点」を参照)。

例

例 1:TZを検証する

ユーザー:「123456782は有効なイスラエルのIDですか?」 結果:アルゴリズムを実行し、説明とともに有効/無効を報告します。

例 2:コードを実装する

ユーザー:「JavaScriptでイスラエルのID検証が必要です」 結果:references/javascript.mdにあるテスト済みの移植版を使用します(IDを文字列として保持し、padStart(9, '0')でゼロ埋めし、指定された区切り文字とASCIIの[0-9]のみを受け付けます)。また、references/id-formats.mdのゴールデンベクトルをユニットテストとして実行します。独自に移植しないでください。Number()によって先頭のゼロが失われることと、\Dで文字を取り除くことが、JavaScript版でよく起きる2つの不具合です。

例 3:テストデータを生成する

ユーザー:「テスト用に有効な会社番号が10個必要です」 結果:テスト用に51-の接頭辞を付けた有効なIDを10個生成します。

同梱リソース

スクリプト
  • scripts/validate_id.py:イスラエルのID番号(Teudat Zehut、会社、amuta、パートナーシップ)を検証、特定、フォーマット、生成します。詳細モードではチェックデジット計算の各手順を表示し、接頭辞を指定したテストIDの一括生成と、あらゆるID番号からの種類の特定に対応します。終了コード:0は有効、1は形式上正しいもののチェックデジット不一致、2は入力形式が不正です。validate --maskはログやCI出力向けに下4桁のみを表示します。実行方法:python scripts/validate_id.py --help
参考資料
  • references/id-formats.md。テウダット・ゼフート、登録法人(50~59の範囲全体:会社、公開会社、パートナーシップ、協同組合、アムタ、信託基金)を含む、イスラエルのすべてのID番号形式の仕様です。発行機関、形式パターン、計算例付きのルーン変種チェックデジットアルゴリズム、有効、桁の入れ替え、1桁違い、すべてゼロ、先頭のゼロの欠落、不正形式を網羅したゴールデンテストベクターの表、一般的な検証エラーを記載しています。検証ロジックの実装時やチェックデジットのエラーをデバッグする際に参照してください。
  • references/javascript.md。Python スクリプトとの相互検証済みの JavaScript 移植版と、JavaScript への移植でよく起きる問題を記載しています。ブラウザーまたは Node での検証が必要な場合に参照してください。

参考リンク

注意点

  • イスラエルのID番号(Teudat Zehut)は必ず9桁で、Luhn(mod 10)チェックデジットが付いています。エージェントがランダムな9桁の数字を生成し、チェックデジットの検証に失敗することがあります。
  • 9桁未満のイスラエルのID番号は、先頭をゼロで埋める必要があります。「12345678」のようなIDは、実際には「012345678」です。エージェントが先頭のゼロを取り除き、検証を壊すことがあります。
  • イスラエルのID番号は日付を符号化していません。数字から生年月日、年齢、出生年、在留資格を推測することはできません。米国のSSNのような直感に基づいて訓練されたエージェントは、この前提をでっち上げることがよくあります。
  • IDの先頭の数字の範囲を基準に、個人IDを入力したり拒否したりしないでください。この番号に市民資格の符号化があるという文書はありません(「範囲による生来の市民と在留者・外国人労働者の区分」は俗説です)。先頭の数字に関係なく、すべての個人IDに同じLuhnチェックが適用されます。すべて単なる9桁のIDとして扱ってください。
  • PII/プライバシーに関するログ記録:イスラエルのIDを未加工のまま、アプリケーションログ、エラーメッセージ、テレメトリー、分析イベントに記録してはいけません。イスラエルのプライバシー保護法は改正第13号によって包括的に改正され(2025年8月14日施行)、重大なセキュリティインシデントはプライバシー保護当局に直ちに報告しなければなりません(次の項目を参照)。許可されていない状況(デバッグUI、サポートツール、顧客向けレシート)でIDを表示する場合、末尾4桁以下のみを表示するようマスキングしてください。例:xxxxx6782。必須ではないストアに保存する前に、データベース外に保持した秘密のペッパーを使ってHMAC-SHA256を適用するか、トークン化ボールトを使用してください。鍵なしの単純なハッシュは保護になりません。鍵空間は10^9未満で、チェックデジットを考慮するとさらに狭まるため、総当たり攻撃でテーブル全体を数秒で復元できます。
  • コードの衛生管理を超えるプライバシーコンプライアンスは、ここでは対象外です。 プライバシー保護当局は改正第13号を執行しており、2026年7月には、改正の施行後初となる金銭制裁として、重大なセキュリティインシデントを当局に直ちに報告しなかった医療保険基金に対し、法定減額後の256,000 NISを科しました。これは情報セキュリティ規則が求める報告であり、当局はインシデントを認知した時点で報告義務が生じると述べています。ID番号のデータベースは、これらの規則の対象となる可能性が高いです。コンプライアンスプログラム自体(セキュリティレベル、インシデント報告、プライバシー保護責任者の任命義務の有無)については、israeli-privacy-shield スキルを利用し、弁護士に確認してください。このバリデーターが対象とするのは、上記のコードレベルのルールのみです。
  • 個人事業主の事業番号は、登録法人に付与される5x番号ではありません。osek patur証明書に記載されるosek番号は、通常、事業主本人の9桁のTeudat Zehutです(5x番号は、法人庁で登録する際に付与されます)。5x番号しか受け付けない「事業番号」フィールドでは、個人事業主が拒否されます。事業番号を尋ねるすべての場所で両方の形式を受け付けてください。どちらにも同じチェックデジットが適用されます。
  • IDF個人番号(mispar ishi)は、IDFが発行する別個の識別子であり、このスキルの対象外です。民間のチェックデジットアルゴリズムを適用しないでください。このスキルにはIDF個人番号のチェックデジットについて記載がないため、検証の合否に意味はありません。
  • 000000000 はLuhnチェックに合格します(数字の合計が0で、10で割り切れるため)が、実在するIDではありません。これはよくあるセンチネル値で、空フィールドの誤検出につながります。空文字列や数値型カラムのデフォルト値が、ゼロ埋めによってそのままこの値になります。「有効」という結果を信頼する前に、すべてゼロの値を明示的に拒否してください。
  • 検証前に数字以外の文字をすべて取り除くと、誤検出が発生します。 一見自然な1行の処理ですが、62819482.1 が 628194821 として検証に合格してしまいます。名前付きの区切り文字セットのみを除去し、それ以外の文字は削除せず、不正な入力として扱ってください。これがバリデーターとフィルターの違いです。
  • IDを逆順にしてもチェックデジットの検証に合格します。 重み1,2,1,2,1,2,1,2,1は逆向きに読んでも同じため、数字を逆順にした9桁のID(視覚的な順序のPDF、OCR、古いシステムから取得した番号など)は必ず検証に合格します。287654321 は 123456782 を逆順にしたもので、検証に合格します。逆順にした8桁の値(先頭のゼロが落ちている場合)だけは、通常、検証に失敗します。チェックデジットでは逆順を検出できないため、番号をユーザーが見ているもの、または入力したものと照合し、有効という結果を数字の順序が正しい証拠として扱わないでください。同じ理由から、双方向テキストの上書き文字や分離文字(U+202A~U+202E、U+2066~U+2069)を決して除去しないでください。"\u202e287654321" は、保存値が287654321である一方、画面には123456782と表示されます。
  • イスラエルのIDは最大9桁なので、チェックサムで失敗させるのではなく、9桁を超える入力を拒否してください。 0000000018 は「無効なID」ではなく、そもそもIDではありません。ユーザーにIDが無効だと伝えると、実際には存在しないタイプミスを探させてしまいます。
  • 生成したテストIDが実在の人物のIDである可能性があります。 チェックデジットに合格しても、その番号が発行済みかどうかは分かりません。生成処理にもそれを知る方法はありません。生成した番号を、開発者のマシンの外に持ち出されるシードデータ、ステージング環境のメール、スクリーンショット、ドキュメント、デモテナントに含めないでください。人に見せる必要のあるフィクスチャには、公開されている例 123456782、または意図的にチェックデジットの検証に失敗する番号を使ってください。
  • 自分のCLI出力もログです。 ターミナルにID全桁を出力すると、シェル履歴やCIログに残ります。末尾4桁のみを出力する scripts/validate_id.py validate --mask を使用してください。--verbose は全桁を出力し、--mask との併用を拒否します。

トラブルシューティング

エラー:「ID は有効に見えますが、認識されません」

原因:チェックディジットは通過していますが、ID は発行されていません。 解決策:このアルゴリズムが検証するのは形式のみで、実在性ではありません。番号が発行されたかどうかを確認できるのは発行機関だけです。企業、パートナーシップ、アムタについては、「参照リンク」にある企業庁の検索を利用してください。このスキルでは、個人 ID の公開検索について説明していません。

エラー:「範囲/プレフィックスのフィルター後に ID の検証に失敗します」

原因:上流のフィルターが先頭の数字の範囲に基づいて ID を拒否している(例:先頭の数字が特定の値なら「個人 ID ではない」と扱う)、または先頭のゼロが落ちて ID が 8 桁で保存されたため、チェックディジットの検証に失敗しています。 解決策:個人 ID は先頭の数字にかかわらず、すべて同じ 9 桁の Luhn チェックを使用します。また、範囲に基づくステータスマッピングに信頼できるものはありません。検証前に先頭にゼロを付けて(zfill(9))9 桁に戻し、先頭の数字による範囲の許可リストを削除してください。なお、先頭が 5 の 9 桁の番号は、通常、個人 ID ではなく登録法人の番号です。

エラー:「長さが一致しない/先頭のゼロが削除されている」

原因:スプレッドシート、JSON パーサー、または数値列が先頭のゼロを削除しました(例:整数として保存された 012345678 が 12345678 になる)。 解決策:ID は必ず文字列として保存してください。読み取り時に、チェックを実行する前に zfill(9)(Python)/padStart(9, '0')(JS)で左側を 9 桁までゼロ埋めしてください。ゼロ埋め後にのみ拒否してください。

エラー:「入力が無効です。ID にハイフンまたは空白が含まれています」

原因:ユーザーが 51-530820-3 や 58 012345 3 のように書式設定された企業番号またはアムタ番号を貼り付けました。 解決策:長さを確認する前に、区切り文字(空白、ハイフンとダッシュ、ノーブレークスペースと狭いノーブレークスペース、ゼロ幅文字)のみを取り除き、先頭と末尾にある空白、タブ、改行、LRM/RLM マークを削除してから、zfill(9) を適用してください(数字の途中にタブまたは改行がある場合は不正な形式です)。人向けに書式設定された形式と数字のみの形式は、どちらも同じように検証される必要があります。

数字以外をすべて削除してはいけません。 re.sub(r'[^0-9]', '', id) は同じ処理に見えますが、実際は違います。問題のある文字を報告せずに削除するため、62819482.1 は有効な ID 628194821 になり、""、"abc"、"!!!!!!!!!" はすべて 000000000 になります。明示的に区切り文字を指定し、それ以外は不正な形式として拒否してください。数字の判定に \d や str.isdigit() も使用しないでください。Python ではどちらもアラビア・インド数字に一致するため、re.sub(r'\D', '', id) を使うと、それらが通過して int() に渡されてしまいます。

エラー:「空欄と不正な ID を区別できません」

原因:バリデーターが単一のブール値を返すため、「ユーザーが空欄のままにした」「ユーザーが文字を入力した」「この ID はチェックディジットに失敗する」がすべて False になり、フォームに誤ったメッセージが表示されます。 解決策:判定結果だけでなく理由も返してください。scripts/validate_id.py は終了コードで 3 つを区別します。0 は有効、1 は形式が正しいもののチェックディジットに失敗、2 は不正な入力です。理由は標準出力に出力されます(MALFORMED - too long: 10 digits、MALFORMED - empty input、MALFORMED - contains characters that are not digits or separators: '.')。テキストではなく終了コードに基づいてスクリプトを作成してください。

エラー:「9 桁の入力なのにアルゴリズムが失敗します」

原因:よくある原因はチェックディジット自体ではなく、ID 本体の数字の入れ替わりや 1 桁の入力ミスです。もう 1 つの原因は、その値が軍の mispar ishi であることです。これは IDF の別の識別子であり、このスキルではチェックディジットについて説明していません(「注意点」を参照)。そのため、検証の失敗はこの識別子について何も示しません。 解決策:元の書類を見ながら ID を再入力するようユーザーに依頼してください。それでも失敗し、ユーザーが正しいと主張する場合は、発行機関に別途確認するよう提案してください。チェックディジットを黙って「修正」してはいけません。

コメント