37

Is it possible to use a regex for parsing an argument? For example, I want to accept an argument if only it is a 32 length hex (i.e. matches /[a-f0-9A-F]{32}/)

I tried

p.add_argument('hex', type=str, nargs="[a-f0-9A-F]{32}")

without success

2
  • 1
    Alternatively, take a look at this question. Commented Jan 26, 2017 at 19:08
  • 1
    argparse does use regex expressions to count argument strings, but it generates the patterns itself. The allowed nargs values like *+?' have a regex feel, but they aren't used directly. They are actually values of module constants (like argparse.ZERO_OR_MORE), and are used in if else` tests. Commented Jan 26, 2017 at 21:08

2 Answers 2

70

The type keyword for add_argument() can take any callable that accepts a single string argument and returns the converted value. If the callable raises argparse.ArgumentTypeError, TypeError, or ValueError, the exception is caught and a nicely formatted error message is displayed.

import argparse
import re 
from uuid import uuid4

def my_regex_type(arg_value, pat=re.compile(r"^[a-f0-9A-F]{32}$")):
    if not pat.match(arg_value):
        raise argparse.ArgumentTypeError("invalid value")
    return arg_value

parser = argparse.ArgumentParser()
parser.add_argument('hex', type=my_regex_type)

args = parser.parse_args([uuid4().hex])
Sign up to request clarification or add additional context in comments.

Comments

8

Improving on wim's answer, you can wrap the regex-checking function as a closure which allows you to reuse the regex checking function with other patterns.

regex_type(pattern) returns a function which, when passed to the type keyword argument, checks the string argument against pattern.

import argparse
import re

def regex_type(pattern: str | re.Pattern):
    """Argument type for matching a regex pattern."""

    def closure_check_regex(arg_value):  
        if not re.match(pattern, arg_value):
            raise argparse.ArgumentTypeError("invalid value")
        return arg_value

    return closure_check_regex

parser = argparse.ArgumentParser()
parser.add_argument("hex", type=regex_type(r"^[a-f0-9A-F]{32}$"))

# Example
from uuid import uuid4

args = parser.parse_args([uuid4().hex])  # this succeeds
args = parser.parse_args(["not-valid"])  # >>> error: argument hex: invalid value

# Reusing the regex_type
parser.add_argument("digits", type=regex_type(r"^\d+$"))

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.