# Invoice Field Regex Generator in Python for OCR Text

> Source: https://netray.co/tools/invoice-field-regex-generator-python
> Publisher: Netray (netray.co), AI and integration engineering for ERP and manufacturing systems.
> Section: Free Tools

## Short answer

Set the labels your suppliers use and get a Python script with regexes for invoice number, PO number, invoice date and total amount, plus a total check.

## Category

developer

## Audience

- ERP developer
- AP automation engineer

## Tool

**Kind:** template

**Output:** code

**Language:** python

**Fields:**

#### Invoice number label(s)

**Key:** inv_label

**Type:** text

**Default:** Invoice No|Invoice #|Inv No

**Help:** Alternatives separated by |

#### PO number label(s)

**Key:** po_label

**Type:** text

**Default:** PO Number|Purchase Order|P.O. No

#### Invoice date label(s)

**Key:** date_label

**Type:** text

**Default:** Invoice Date|Date

#### Total label(s)

**Key:** total_label

**Type:** text

**Default:** Total Due|Amount Due|Grand Total|Total

#### Currency symbol

**Key:** currency

**Type:** text

**Default:** $

#### Total check tolerance

**Key:** tolerance

**Type:** number

**Default:** 0.01

**Blocks:**

#### Patterns

**Body:** import re
from datetime import datetime

CUR = re.escape("{{currency}}")

INVOICE_NO = re.compile(r"(?:{{inv_label}})\s*[:#.]?\s*([A-Z0-9][A-Z0-9\-/]{3,24})", re.I)
PO_NO = re.compile(r"(?:{{po_label}})\s*[:#.]?\s*([A-Z0-9][A-Z0-9\-/]{3,24})", re.I)
DATE_TXT = re.compile(r"(?:{{date_label}})\s*[:.]?\s*(\d{4}-\d{2}-\d{2}|\d{1,2}[/.-]\d{1,2}[/.-]\d{2,4})", re.I)
TOTAL = re.compile(r"(?:{{total_label}})\s*[:.]?\s*" + CUR + r"?\s*([0-9]{1,3}(?:,[0-9]{3})*(?:\.[0-9]{2})|[0-9]+(?:\.[0-9]{2})?)", re.I)
LINE_AMT = re.compile(r"^.*?" + CUR + r"?\s*([0-9]{1,3}(?:,[0-9]{3})*\.[0-9]{2})\s*$", re.M)

#### Parser

**Body:** def first(pattern, text):
    m = pattern.search(text)
    return m.group(1).strip() if m else None

def parse_date(raw):
    if not raw:
        return None
    for fmt in ("%Y-%m-%d", "%d/%m/%Y", "%d-%m-%Y", "%d.%m.%Y", "%m/%d/%Y", "%d/%m/%y"):
        try:
            return datetime.strptime(raw, fmt).date().isoformat()
        except ValueError:
            continue
    return None

def parse_amount(raw):
    return float(raw.replace(",", "")) if raw else None

def parse_invoice(text):
    result = {
        "invoice_number": first(INVOICE_NO, text),
        "po_number": first(PO_NO, text),
        "invoice_date": parse_date(first(DATE_TXT, text)),
        "total": parse_amount(first(TOTAL, text)),
    }
    result["flags"] = []
    for key in ("invoice_number", "invoice_date", "total"):
        if result[key] is None:
            result["flags"].append("missing_" + key)
    return result

#### Total check against line amounts

**Body:** def check_total(text, parsed, tolerance={{tolerance}}):
    amounts = [parse_amount(a) for a in LINE_AMT.findall(text)]
    if not amounts or parsed["total"] is None:
        return "cannot_check"
    # the last amount on a page is usually the total, so exclude it from the sum
    body = amounts[:-1]
    if abs(sum(body) - parsed["total"]) <= tolerance:
        return "ok"
    return "review"

if __name__ == "__main__":
    sample = open("invoice.txt", encoding="utf-8").read()
    data = parse_invoice(sample)
    data["total_check"] = check_total(sample, data)
    print(data)

**Notes:** This is a starting point for text-based extraction, not a complete product. It assumes decimal point amounts, so adapt the amount pattern and parse_amount for decimal comma locales. The total check is a heuristic that ignores tax and freight lines; replace it with line level logic that matches your invoice layouts. Test on real supplier samples before relying on it.

## Content

**Intro:** For suppliers with stable layouts, a few well tested regular expressions beat a heavy model: they are fast, explainable and easy to audit. This generator builds a Python parser for the four fields every AP team needs, with a basic total check.

**Sections:**

#### How to use the generator

**Body:** List the labels your suppliers print, separated by a vertical bar, then set the currency symbol and total tolerance. Copy the script, save OCR text from your engine into invoice.txt, and run it. The output is a dictionary with the invoice number, PO number, ISO date and total, plus flags for missing mandatory fields. Extend the label lists as you meet new supplier layouts, and keep one test text file per supplier so changes do not break old ones.

#### Design of the patterns

**Body:** Each pattern looks for a label, an optional separator such as a colon or hash, and then a value shaped like the field. Invoice and PO numbers allow letters, digits, hyphens and slashes, with a minimum length to avoid matching words. The date pattern accepts ISO dates and numeric day, month and year forms. The amount pattern accepts thousands commas and two decimals.

**Bullets:**

- Labels are case-insensitive alternatives
- Longer labels should come before shorter ones, so Total Due matches before Total
- Dates are normalized to ISO format
- Missing mandatory fields raise flags rather than silent blanks

#### Where regex stops working

**Body:** Regex works when the label and value sit on the same line. It struggles with tables, labels above values, multi column layouts, handwritten notes and scans with heavy noise. Ambiguous dates such as 04/05/2026 cannot be resolved by pattern alone, so decide the order per supplier or country. When the number of layouts grows, move to a layout-aware extraction approach and keep regex for validation.

#### Common mistakes

**Body:** A pattern that matches the first Total in the text may pick up a subtotal. Prefer the last match on the page, or anchor to the words Amount Due. Another mistake is skipping validation: pair every extracted value with a check such as date range, duplicate invoice detection by supplier and number, and the total comparison.

**Cta:** If you need extraction that handles many layouts and writes validated results back to your ERP, Netray can build it as a private service on your infrastructure.

**Faq:**

#### Can regex extract data from any invoice?

**Answer:** No. It suits invoices where the label and value appear on one line in a consistent form. For varied layouts, tables and noisy scans you need layout-aware extraction, with regex kept for validating the results.

#### How do I handle dates like 04/05/2026?

**Answer:** Pattern matching cannot tell whether that is April 5 or May 4. Store the expected date order per supplier or country, and apply that order first. Reject dates that fall outside a plausible range around the receipt date.

#### How do I support decimal comma amounts?

**Answer:** Change the amount pattern to use dots for thousands and a comma for decimals, and update parse_amount to remove dots and replace the comma with a dot. Select the pattern per supplier locale rather than guessing from the text.

#### Why is my total picking up the subtotal?

**Answer:** The word Total also appears inside Subtotal. List the more specific labels first, use word boundaries, and prefer the last match in the text, since final totals usually appear at the end of the page.

## Search terms

regex invoice number python, extract invoice total from ocr text regex, python parse invoice text, regex invoice date dd/mm/yyyy, extract po number from invoice regex, ocr invoice text parsing python, invoice regex examples

---
Talk to an engineer: https://netray.co/contact?intent=erp_ai | Machine catalog: https://netray.co/agent/catalog.json
