mcpField
I
israeli-id-validator

israeli-id-validator

github.com/skills-il开发13168 次安装3 天前更新
代码仓库

关于 israeli-id-validator

israeli-id-validator 是用于校验和处理以色列个人及注册实体编号的技能。它说明校验位规则、安全输入处理和类型标注限制,并附有 Python 与 JavaScript 参考。

主要功能

  1. 01以色列编号校验位验证
  2. 02个人及实体格式指南
  3. 03生成开发测试编号
  4. 04支持批量与遮罩模式的 Python 命令行工具
  5. 05JavaScript 实现参考
  6. 06输入处理与隐私防护

适用场景

  1. 01检查以色列编号格式
  2. 02为本地开发测试生成编号
  3. 03在浏览器或 Node 中实现校验
  4. 04在命令行和 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

详细介绍

以色列身份证号码验证器

说明

步骤 1:识别 ID 类型
类型前缀长度示例备注
Teudat Zehut(个人 ID)无(无法推断)9 位数字123456782这些数字不包含出生日期、年龄或居留身份信息
公司/注册实体通常以 5 开头9 位数字51-530820-3前两位通常与实体类型相关(代码 50-59,见下表),这只是可能的标签,并非规则。校验位算法与个人 ID 相同

公司和注册实体代码(前两位):

前缀实体
50政府公司、养老金/公积金或地方委员会
51私营公司(Chevra Ba'am / Ltd)
52上市公司
53授权时期合伙企业(Shutafut Mandatorit,英国托管时期)
54普通合伙企业
55合伙企业(Shutafut)
56外国公司
57合作社(Aguda Shitufit)/基布兹
58Amuta(非营利组织)/公益公司
59捐赠基金(Hekdesh),本身不是公司

基于前缀的类型判断只是一种启发式方法:以 5 开头的 9 位数字通常属于注册实体(资料称前两位“通常”与实体类型相关,且所有列出的代码都以 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 版本最常出错的两种方式。

示例 3:生成测试数据

用户提问:“我需要 10 个有效的公司号码用于测试。” 结果:生成 10 个以 51- 开头的有效 ID 用于测试。

附带资源

脚本
  • scripts/validate_id.py ,用于验证、识别、格式化和生成以色列 ID 号码(Teudat Zehut、公司、amuta、合伙企业)。支持详细模式,逐步显示校验位计算过程;支持通过控制前缀批量生成测试 ID;也支持从任何 ID 号码识别类型。退出代码:0 表示有效,1 表示格式正确但校验位不通过,2 表示输入格式错误。validate --mask 只会显示末 4 位,用于日志和 CI 输出。运行:python scripts/validate_id.py --help
参考资料
  • references/id-formats.md,介绍所有以色列身份证号码格式的规范,包括 Teudat Zehut、注册实体(完整的 50–59 号段:公司、上市公司、合伙企业、合作社、amuta、遗赠基金)及其签发机构、格式模式、附带演算示例的 Luhn 变体校验位算法、黄金测试向量表(有效、数字换位、差一、全零、漏掉前导零、格式错误)和常见验证错误。实现验证逻辑或排查校验位失败问题时请查阅。
  • references/javascript.md,提供与 Python 脚本交叉验证的 JavaScript 移植版,以及 JavaScript 移植通常会出错的地方。用户需要在浏览器或 Node 中进行验证时请使用。

参考链接

注意事项

  • 以色列身份证号(Teudat Zehut)恰好为 9 位数字,并带有 Luhn(模 10)校验位。Agent 可能会生成随机的 9 位数字,但这些数字无法通过校验位验证。
  • 少于 9 位的以色列身份证号必须在左侧补零。像 "12345678" 这样的 ID 实际上是 "012345678"。Agent 可能会去掉前导零,导致验证失败。
  • 以色列身份证号不以日期编码。无法根据数字推断出生日期、年龄、出生年份或居留身份。受美国 SSN 直觉影响而训练的 Agent 往往会臆造这种假设。
  • 不要根据个人 ID 的首位数字范围输入或拒绝该 ID。数字中没有记录在案的公民身份编码(常见的“按范围区分本地人、居民与外籍劳工”的说法只是传闻)。所有个人 ID,无论首位数字是什么,都通过相同的 Luhn 校验;应一律将其视为普通的 9 位 ID。
  • PII / 隐私日志记录:绝不要在应用程序日志、错误消息、遥测或分析事件中记录未脱敏的以色列 ID。以色列《隐私保护法》已由第 13 号修正案全面修订(于 2025 年 8 月 14 日生效),发生严重安全事件时必须立即向隐私保护局报告(见下一项)。在非授权场景(调试 UI、支持工具、面向客户的收据)中显示 ID 时,最多只显示末尾 4 位,例如 xxxxx6782。持久化到非必要存储之前,应使用密钥保存在数据库之外的 HMAC-SHA256,或使用令牌化保险库。未加密的 ID 哈希并不能提供保护:整个可能值空间不到 10^9,校验位还会进一步缩小范围,因此只需几秒钟就能通过暴力破解还原整张表。
  • 超出代码规范范围的隐私合规事项不在此处讨论。 隐私保护局正在执行第 13 号修正案:2026 年 7 月,在修正案生效后首次处以罚款(法定减额后为 256,000 NIS,罚款对象为一家医疗基金),原因是未按《信息安全条例》要求立即向隐私保护局报告严重安全事件;该局还表示,报告义务在事件为人所知时即产生。身份证号数据库很可能受这些条例约束。关于合规计划本身(安全级别、事件报告、是否必须任命隐私保护官),请使用 israeli-privacy-shield 技能并咨询法律顾问;此验证器仅涵盖上述代码层面的规则。
  • 个体经营者的企业编号不是 5x 开头的注册实体编号:个体经营者豁免登记证上的 osek 编号通常是经营者本人的 9 位 Teudat Zehut(在公司管理局注册时会分配 5x 开头的编号)。只接受 5x 开头编号的“企业编号”字段会拒绝个体经营者。凡是要求填写企业编号的地方,都应接受这两种格式;两者都通过相同的校验位检查。
  • IDF 个人编号(mispar ishi)是由 IDF 签发的独立标识符,不在此技能的范围内。不要用平民身份证号的校验位算法处理它:本技能未说明其校验位规则,因此通过或失败的结果都没有意义。
  • 000000000 可以通过 Luhn 校验(其数字之和为 0,可被 10 整除),但它从来不是真实 ID。这是常见的哨兵值 / 空字段误判:空字符串或默认值为零的数值列经过左侧补零后,就会变成这个值。应明确拒绝全零值,不要仅凭“有效”结果就信任它。
  • 验证前去掉所有非数字字符,会导致误报。 这是看起来最自然的一行代码,却会让 62819482.1 被验证为 628194821。只移除指定的分隔符;其他内容一律视为格式错误输入,而不是直接删除。这就是验证器与过滤器的区别。
  • 反转后的 ID 仍然能通过校验位检查。 权重 1、2、1、2、1、2、1、2、1 正反读都相同,因此,数字顺序被反转的 9 位 ID(例如从视觉顺序的 PDF、OCR 或旧系统中提取的号码)总是能通过验证:287654321 是 123456782 的反转形式,并且能通过校验。只有去掉前导零后的 8 位值通常无法通过。校验位无法检测反转,因此应将号码与用户看到或输入的内容进行比对,绝不要把 VALID 当作数字顺序正确的证明。出于同样的原因,绝不要丢弃双向覆盖或隔离字符(U+202A 至 U+202E、U+2066 至 U+2069):"\u202e287654321" 在屏幕上显示为 123456782,但存储的值却是 287654321。
  • 以色列 ID 最多为 9 位,因此应拒绝更长的输入,而不是让它因校验和不匹配而失败。 0000000018 不是“无效 ID”,它根本就不是 ID;告诉用户 ID 无效,会让他们去找一个其实并不存在的输入错误。
  • 生成的测试 ID 可能是真实用户的 ID。 通过校验位并不能说明该号码是否已被签发,而生成器也无法得知。绝不要让生成的号码进入会离开开发者本机的种子数据、暂存环境邮件、屏幕截图、文档或演示租户中。如果必须向他人展示测试数据,请使用已发布的示例 123456782,或使用一个故意无法通过校验位检查的号码。
  • 你自己的 CLI 输出也是日志。 在终端中打印完整 ID 会使其进入 Shell 历史记录和 CI 日志。请使用 scripts/validate_id.py validate --mask,它只会打印末尾 4 位;--verbose 会打印每一位,且不能与 --mask 同时使用。

故障排除

错误:“ID 看起来有效,但无法识别”

原因:校验位通过了,但该 ID 尚未签发。 解决方案:该算法只验证格式,不验证是否存在。只有签发机构才能确认某个号码是否已签发:对于公司、合伙企业和 amuta,请参阅参考链接中的公司管理局搜索。本技能未记录个人 ID 的公开查询方式。

错误:“经过范围/前缀筛选后,ID 未通过验证”

原因:上游筛选器根据首位数字的范围拒绝 ID(例如,将某个首位数字视为“非个人 ID”),或者 ID 原本以 8 位数字存储,导致前导零被丢弃,进而使校验位验证失败。 解决方案:所有个人 ID 都使用相同的 9 位 Luhn 校验,不受首位数字影响,而且不存在可靠的按范围映射状态的方法。验证前,先补齐前导零(zfill(9)),并移除任何首位数字范围白名单。请注意,以 5 开头的 9 位数字通常是已注册实体的号码,而非个人 ID。

错误:“长度不匹配/前导零被丢弃”

原因:电子表格、JSON 解析器或数值列丢弃了前导零(例如,012345678 作为整数存储后变成 12345678)。 解决方案:始终将 ID 存储为字符串。读取时,先在左侧补齐至 9 位,再运行校验:Python 使用 zfill(9),JS 使用 padStart(9, '0')。只有补齐后才拒绝。

错误:“输入无效,ID 中含有连字符或空格”

原因:用户粘贴了带格式的公司或 amuta 号码,例如 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 使用退出码区分这三种情况:0 表示有效,1 表示格式正确但校验位不通过,2 表示输入格式错误;具体原因会输出到标准输出(MALFORMED - too long: 10 digits、MALFORMED - empty input、MALFORMED - contains characters that are not digits or separators: '.')。请根据退出码编写脚本,而不是根据文本。

错误:“输入有 9 位,但算法验证失败”

原因:常见原因是 ID 主体部分发生了数字调换或单个数字输入错误,而非校验位本身。另一个原因是该值为军方的 mispar ishi,这是独立的 IDF 标识符,本技能未记录其校验位(请参阅注意事项),因此验证失败并不能说明该标识符有误。 解决方案:请用户根据源文件重新输入 ID。如果仍然验证失败,但用户坚持认为 ID 正确,请建议通过其他渠道向签发机构核实;不要擅自“修正”校验位。

评论

支持 Markdown