Skip to content

Indian recognizers miss numbers written in Indian-script digits (Aadhaar, PAN) #2481

Open

Description

@Malaya-kumar-swain

Describe the bug

InAadhaarRecognizer and InPanRecognizer only match ASCII digits ([0-9]), so the same number written with Devanagari, Odia or Bengali digits is not detected. People in India do write numbers this way, in regional-language forms, chat messages and OCR output from scanned documents.

To reproduce (presidio-analyzer 2.2.366, synthetic test number)

from presidio_analyzer.predefined_recognizers import InAadhaarRecognizer

r = InAadhaarRecognizer()
for text in ["My Aadhaar number is 2345 6789 0124",
             "My Aadhaar number is २३४५ ६७८९ ०१२४",   # Devanagari digits
             "My Aadhaar number is ୨୩୪୫ ୬୭୮୯ ୦୧୨୪"]:  # Odia digits
    print(r.analyze(text, ["IN_AADHAAR"], None))

The ASCII version is found with score 1.0. The Devanagari and Odia versions return an empty list. The same happens with PAN, for example ABCPE१२३४F.

Expected behavior

The same number is detected whichever digit script it is written in.

Possible approach

Map Unicode decimal digits to ASCII before matching. The mapping is one character to one character, so start and end offsets stay exactly the same. Two options:

  1. Do it only in the Indian recognizers (Aadhaar, PAN, GSTIN, passport, voter, vehicle). This is the smaller change.
  2. Make it an option on PatternRecognizer, so other countries with their own digit scripts can use it too.

Option 1 seems safer as a first step, since it only adds detections and leaves current ASCII results unchanged. It would include tests for each Indian digit script, unchanged ASCII results, exact offsets, and look-alike values that must still not match.

Would this be welcome, and which option would you prefer? I am happy to open a PR.

For context, I maintain Vismriti, a small library for India's DPDP Act that handles this case for Aadhaar.

Activity

  1. Shellghostt commented on Nov 15, 2026

    @Shellghostt

    Hi, I would like to work on this, but you should know that another PR is already in flight on the same issue.

    PR #2480 now says it fixes both #2377 and #2481, and its latest commit adds Devanagari, Bengali and Odia digit tests to the Aadhaar and PAN test files, so it overlaps with the two recognizers named in this issue. I have a narrower implementation ready and I am opening it as a pull request rather than claiming the issue, so you can compare the two and take whichever fits your preference.

    The differences are these. First, the digit set. My change matches ASCII plus the nine Indic digit blocks, Devanagari, Bengali, Gurmukhi, Gujarati, Oriya, Tamil, Telugu, Kannada and Malayalam, and deliberately leaves Thai, Arabic-Indic, Persian and fullwidth digits matching nothing, since those scripts are not used to write Indian identifiers. PR #2480 folds every Unicode decimal digit into ASCII, so it covers those other scripts as well. Second, the blast radius. My change edits only the two recognizers named in the title and touches no shared code path, so no other recognizer changes behavior, no custom pattern changes meaning, and no deny list changes meaning. PR #2480 changes PatternRecognizer and IbanRecognizer, which affects every pattern recognizer in the library and therefore every user's detection results, on by default. Both recognizers I touch ship with enabled: false, so a user who has not enabled them sees no difference at all. Third, the coverage. PR #2480 covers Devanagari, Bengali and Odia. My change covers all nine Indic scripts for both recognizers, plus the separated Aadhaar form, plus a checksum rejection written in an Indic script, plus Thai, Arabic-Indic and fullwidth digits as negatives, plus a context enhancement comparison, plus a configuration path test that enables each recognizer through RecognizerRegistryProvider. Coverage on the changed lines is 100 percent.

    I kept the scope to the two recognizers named in the title. The other Indian recognizers, GSTIN, passport, voter and vehicle registration, mix digit ranges with literal digit values such as [1-9], which one shared digit class cannot express, so they would need per-digit classes and I would do that as a follow-up if you want it.

    If you would rather solve this once through the text normalizer that jamesconwaydev mentioned on PR #2480, I am happy to close my pull request and follow that route instead. The Aadhaar checksum needs no change either way, because int() already accepts those digits, so the Verhoeff validation still rejects a bad number written in any of those scripts.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions