Package: qre
qre - like re, but cuterSamplesPattern"* pattern"Input"First pattern"Result👍🏼Pattern"World's [] pattern"Input"World's coolest pattern"Result["coolest"]Pattern"product id: [product_id], units: [units: int], price: [unit_price: decimal]"Input"Product ID: A123, Units: 3, Price: 1.23"(case-insensitive)Result{"product_id": "A123", "units": 3, "unit_price": Decimal("1.23")}This package owes everything, including most of the codebase, to Thomas Feldtmann'ssimplematch. All poor design decisions are mine.
Seethis collectionfor other alternatives.Status: Comprehensively tested but never used for anything real. All evolution is expected to be
incremental.Quick startpip install qreMy first little match:importqreassertqre.search("in [place]","Match made in heaven")=={"place":"heaven"}qreis mostly focused on collecting named groups from the input strings, so the return value is
an easy-to-access dict. Groups are denoted with brackets, which means that patterns are friendly
with f-strings.For unnamed groups the returned object has been tweaked a little bit - they can be found as a list
in theunnamedattribute:assertqre.match("[] [:int]","Lesson 1").unnamed==["Lesson",1]Type specifiers can be used with both named and unnamed groups. They act both as specs for the
pattern to find and, when applicable, as converters to the right type.Currently available types are:intfloatdecimaldate(ISO)datetime(ISO)uuidlettersidentifier(lettersplus numbers and underscore)emailurlipv4ipv6creditcardopen(any one of(,[,{)close(),], or})You can register your own types and conversions withregister_type(name, regex, converter=str).
Asqre's goal is not to replicate the functionality of re, this can also act as the "escape hatch"
when you need just a little bit more than whatqreoffers.Here's how to useregister_typeto turn an emoji into a textual description:qre.register_type("mood",r"[😀😞]",lambdaemoji:{"😀":"good","😞":"bad"}.get(emoji,"unknown"))assertqre.search("[mood:mood]","I'm feeling 😀 today!")=={"mood":"good"}Note thatregister_typemanipulates a global object, so you only need to register custom types
once, probably somewhere towards the start of your program.PRs for generally useful types are highly welcome.Matching functionsMatching functions expect apatternand astringto match against. The optionalcase_sensitiveargument is true by default.match- Matchpatternagainst the whole of thestringmatch_start- Matchpatternagainst the beginning of thestringmatch_end- Matchpatternagainst the end of thestringsearch- Return the first match of thepatternin thestringsearch_all- Return all matches of thepatternin thestringas a listAll of the functions always return an object that is either truthy or falsy depending on whether
there was a match or not. They never returnNone, and theunnamedattribute contains at least an
empty list, so the returned object is always safe to iterate.Alternatively, you can use the Matcher object. It has the following useful attributes:regexfor debugging the generated regex, or for copying it for use with plainreconvertersfor debugging the converters in usematcher=qre.Matcher("value: [quantitative:float]|[qualitative]",case_sensitive=False)assertmatcher.match("Value: 1.0")=={"quantitative":1.0}# Or any of the other functions aboveassertmatcher.regex=="value:\\(?P<quantitative>[+-]?(?:[0-9]*[.])?[0-9]+)|(?P<qualitative>.*)"assertmatcher.converters=={'quantitative':float}As a final usage scenario, you can callqreon the command line:$ python qre.py
usage: qre.py [-h] [--regex] pattern stringPattern syntax summaryWildcards:*- any character 0+ times+- any 1 character?- any 1 character, maybeOperators:|- either of two characters or groupsGroups:[name]- named group called "name", returned in the main dict.[]- unnamed group, returned in theunnamedlist[name:4],[:4]- group that is 4 characters wide[name:int],[:int]- group that matches the type and is converted to that Python typeEscaping:[*],[+],[?],[|]- literal symbol, not wildcard[[,]]- literal brackets, not groups