Skip to content

Latest commit

 

History

History
530 lines (380 loc) · 14.5 KB

usage.md

File metadata and controls

530 lines (380 loc) · 14.5 KB

Using Regular Expression Patterns in Prolog (pure_regex)

This document provides usage examples and pattern matching examples with expected Prolog toplevel outputs for the pure_regex library.

To load the regular expression engine, run:

?- use_module(library(pure_regex)).
   true.

Usage Examples

1. Direct Pattern Match with phrase/2

Match a string directly against a regular expression pattern using phrase/2. When a pattern is written as a literal character list ("...") or atom ('...'), pure_regex compiles it ahead of time via goal_expansion/2 and inlines the compiled automaton term directly into the clause. Patterns compiled from literals bypass the dynamic compilation cache entirely, saving heap memory and avoiding cache lookup overhead. When a pattern is supplied dynamically at runtime via a variable, it is compiled on first use and cached in the dynamic pattern database.

?- phrase(re_match("a.*b", Match), "acb").
   Match = "acb"
;  false.

2. Pattern Compilation

Compile a regular expression pattern string into a reusable compiled structure.

?- re_compile("a.*b", Compiled).
   Compiled = compiled_tree(sym(char(a),star(sym(dot,end,stp),sym(char(b),end,stp)),stp),0)
;  false.

3. Match using Compiled Pattern

Execute a pre-compiled pattern inside phrase/2 for maximum performance. Passing a pre-compiled pattern to re_match//1-2 avoids both pattern parsing overhead and cache lookup overhead on subsequent matches.

?- re_compile("a.*b", Compiled), phrase(re_match(Compiled, Match), "acb").
   Compiled = compiled_tree(sym(char(a),star(sym(dot,end,stp),sym(char(b),end,stp)),stp),0)
   Match = "acb"
;  false.

4. Inspect Compiled Pattern Cache (Runtime Dynamic Patterns)

Inspect the dynamic compilation cache using re_cache_info/2 to check the number of cached patterns and their pattern keys. Statically compiled literal patterns bypass this cache (Count = 0). When patterns are passed dynamically via variables at runtime, they enter the dynamic cache:

?- re_clear_cache, P1 = "a.*b", phrase(re_match(P1), "acb"), P2 = "[0-9]+", phrase(re_match(P2), "123"), re_cache_info(Count, Keys).
   Count = 4
   Keys = ["a.*b", "a.*b", "[0-9]+", "[0-9]+"]
;  false.

5. Clear Compiled Pattern Cache

Clear all compiled pattern goals from the dynamic compilation database using re_clear_cache/0. Note that re_clear_cache/0 is intended for the rare circumstance that an excessive number of distinct patterns have been compiled, resulting in excessive memory use by the Prolog system. In normal operation, compiled pattern caching provides substantial performance benefits without requiring manual invalidation.

?- re_clear_cache, re_cache_info(Count, Keys).
   Count = 0
   Keys = ""
;  false.

Compile-Time Static Compilation & Expansion Modes

pure_regex provides compile-time macro expansion to eliminate pattern compilation latency at runtime:

  • Approach A (Default, Goal Expansion): When a literal character list ("...") or atom ('...') is passed to re_match/2-3, re_match_groups/4-5, or re_match_named/4-5, goal_expansion/2 compiles the pattern during file loading. The resulting automaton is embedded directly as a constant term in the compiled clause. Patterns compiled from literals bypass the dynamic pattern cache entirely.
  • Approach B (DCG Rule Generation via re_rule//0): Define dedicated, named DCG grammar rules directly from regular expressions at compile time:
    re_rule(ident//0, "^[a-zA-Z_][a-zA-Z0-9_]*$").
    re_rule(ident_match(Match)//0, "^[a-zA-Z_][a-zA-Z0-9_]*$").
    re_rule(ident_groups(Match, Groups)//0, "^([a-z]+)-([0-9]+)$").
  • Default Engine Selection: Set the default regex engine globally via user:regexp_engine(Engine) (rt [default] or dcg).
  • Static Compilation Toggle: Enable or disable compile-time macro expansion via user:regexp_static_compilation(true | false). When false, literal patterns pass through to runtime dynamic matching.
  • Independent Static / Dynamic Overrides: Override matching engines separately:
    • user:regexp_static_engine(Engine): overrides the engine used for compile-time static compilation (rt or dcg).
    • user:regexp_dynamic_engine(Engine): overrides the engine used for runtime dynamic pattern matching (rt or dcg).
  • Expansion Strategy Mode: Select the expansion strategy via user:regexp_expansion(Mode) (term [default, Approach A] or rules [Approach B]).

Pattern Examples

1. Simple Literal Match

Basic matching of a literal character sequence.

?- phrase(re_match("abc", Match), "abc").
   Match = "abc"
;  false.

3. Alternation Precedence

Matching either sub-expression in alternation.

?- phrase(re_match("a|bc", Match), "bc").
   Match = "bc"
;  false.

4. Grouping with Alternation

Explicit precedence using grouping parentheses.

?- phrase(re_match("(a|b)c", Match), "ac").
   Match = "ac"
;  false.

5. Greedy Star Quantifier

Match zero or more times greedily.

?- phrase(re_match("a*", Match), "aaa").
   Match = "aaa"
;  false.

6. Greedy Plus Quantifier

Match one or more times greedily.

?- phrase(re_match("a+", Match), "aa").
   Match = "aa"
;  false.

7. Optional Quantifier (Match)

Match zero or one time greedily (optional matches).

?- phrase(re_match("a?", Match), "a").
   Match = "a"
;  false.

8. Optional Quantifier (Empty)

Match zero or one time greedily (empty match).

?- phrase(re_match("a?", Match), "").
   Match = ""
;  false.

9. Exact Repetition Quantifier

Match exactly N times.

?- phrase(re_match("a{3}", Match), "aaa").
   Match = "aaa"
;  false.

10. Range Repetition Quantifier

Match between N and M times greedily.

?- phrase(re_match("a{2,4}", Match), "aaaa").
   Match = "aaaa"
;  false.

11. Single Group Capture

Extract substrings captured by groups. Captured groups are returned in group-number order (left-to-right based on the position of their opening parentheses). See: https://docs.oracle.com/javase/tutorial/essential/regex/groups.html

?- phrase(re_match_groups("(abc)", Match, Groups), "abc").
   Match = "abc"
   Groups = ["abc"]
;  false.

12. Nested Group Capture

Extract substrings captured by nested groups. The groups are returned in group-number order (left-to-right based on the position of their opening parentheses), so the outer group comes first. See: https://docs.oracle.com/javase/tutorial/essential/regex/groups.html

?- phrase(re_match_groups("(a(b)c)", Match, Groups), "abc").
   Match = "abc"
   Groups = ["abc", "b"]
;  false.

13. Star on Empty String

Edge case: greedy star matching empty string.

?- phrase(re_match("a*", Match), "").
   Match = ""
;  false.

14. Nested Stars

Edge case: nested star operator.

?- phrase(re_match("(a*)*", Match), "a").
   Match = "a"
;  false.

15. Character Classes (Simple)

Match any single character listed in brackets.

?- phrase(re_match("[abc]", Match), "b").
   Match = "b"
;  false.

16. Character Classes (Negated)

Match any single character not listed in brackets.

?- phrase(re_match("[^abc]", Match), "d").
   Match = "d"
;  false.

17. Wildcard Dot

Match any single character except newline.

?- phrase(re_match("a.c", Match), "abc").
   Match = "abc"
;  false.

18. Builtin Digit Class

Match any digit character via \d.

?- phrase(re_match("\\d", Match), "5").
   Match = "5"
;  false.

19. Builtin Word Class

Match any alphanumeric character plus underscore via \w.

?- phrase(re_match("\\w", Match), "x").
   Match = "x"
;  false.

20. Start-of-Line Anchor

Match beginning of the input string via ^.

?- phrase(re_match("^a", Match), "a").
   Match = "a"
;  false.

21. End-of-Line Anchor

Match end of the input string via $.

?- phrase(re_match("a$", Match), "a").
   Match = "a"
;  false.

22. Non-Greedy Quantifier

Match minimal number of repetitions via *?.

?- phrase(re_match("a*?", Match), "a").
   Match = "a"
;  false.

23. Positive Lookahead Assertion

Match pattern only if followed by lookahead sub-expression.

?- phrase(re_match("a(?=b)b", Match), "ab").
   Match = "ab"
;  false.

24. Named Group Capture

Syntax support for named capturing groups using re_match//2 for full pattern matching, and re_match_named//3 with re_group/3 to extract named captured subgroups.

?- phrase(re_match_named("(?P<first>[a-z]+) ([a-z]+) (?P<last>[a-z]+)", Match, Named), "john middle doe"), re_group(Named, first, First).
   Match = "john middle doe"
   Named = [last-[d,o,e],first-[j,o,h,n]]
   First = "john"
;  false.

25. Inline Case-Insensitive Flag

Enable case-insensitivity using inline flags.

?- phrase(re_match("(?i)abc", Match), "ABC").
   Match = "ABC"
;  false.

26. Compile and Match

Manually compile a pattern and execute matching.

?- re_compile("a*b", Compiled), phrase(re_match(Compiled, Match), "aaab").
   Compiled = compiled_tree(star(sym(char(a),end,stp),sym(char(b),end,stp)),0)
   Match = "aaab"
;  false.

27. DCG Phrase Matcher Helper

Use DCG interface re_match//2 inside phrase/3.

?- phrase(re_match("a*b", Match), "aaabc", "c").
   Match = "aaab"
;  false.

28. DCG Phrase Matcher with Groups

Use DCG interface re_match_groups//3 with groups inside phrase/3. Captured groups are returned in group-number order (left-to-right based on the position of their opening parentheses). See: https://docs.oracle.com/javase/tutorial/essential/regex/groups.html

?- phrase(re_match_groups("(a*)b", Match, Groups), "aaabc", "c").
   Match = "aaab"
   Groups = ["aaa"]
;  false.

29. DCG Phrase Matcher with Compiled Pattern

Use re_match//2 with a pre-compiled pattern.

?- re_compile("a*b", Compiled), phrase(re_match(Compiled, Match), "aaabc", "c").
   Compiled = compiled_tree(star(sym(char(a),end,stp),sym(char(b),end,stp)),0)
   Match = "aaab"
;  false.

30. DCG Phrase Matcher with Compiled Pattern and Groups

Use re_match_groups//3 with a pre-compiled pattern and group extraction. Captured groups are returned in group-number order (left-to-right based on the position of their opening parentheses). See: https://docs.oracle.com/javase/tutorial/essential/regex/groups.html

?- re_compile("(a*)b", Compiled), phrase(re_match_groups(Compiled, Match, Groups), "aaabc", "c").
   Compiled = compiled_tree(cap_open(0,star(sym(char(a),end,stp),cap_close(0,sym(char(b),end,stp)))),1)
   Match = "aaab"
   Groups = ["aaa"]
;  false.

31. Compilation Cache Inspection

Access and verify the internal compilation cache.

?- re_clear_cache, phrase(re_match("c*d", Match), "cccd"), re_cache_info(Count, Keys).
   Match = "cccd"
   Count = 0
   Keys = ""
;  false.

32. Compilation Cache Clearing

Clear the cache database and verify no patterns remain. Intended for rare situations where excessive compiled patterns cause high memory use.

?- re_clear_cache, phrase(re_match("c*d", Match), "cccd"), re_clear_cache, re_cache_info(CountAfter, KeysAfter).
   CountAfter = 0
   KeysAfter = ""
;  false.

33. Unanchored Match (showing rest of input)

Match pattern inside input using phrase/3.

?- phrase((..., re_match("aa", Match)), "bbbbaaccccc", Rest).
   Match = "aa"
   Rest = "ccccc"
;  false.

34. Unanchored Match (no rest of input)

Match pattern inside input using phrase/2 (requires matching remaining suffix).

?- phrase((..., re_match("aa", Match), ...), "bbbbaaccccc").
   Match = "aa"
;  false.

35. Nested Captures 4-Deep (3 Top-Level)

Extract groups from a pattern of three captures containing nested captures 4 deep. Captured groups are returned in group-number order (left-to-right based on the position of their opening parentheses). Nested groups follow their enclosing group. See: https://docs.oracle.com/javase/tutorial/essential/regex/groups.html

?- phrase(re_match_groups("(a(b(c(d))))(e(f(g(h))))(i(j(k(l))))", Match, Groups), "abcdefghijkl").
   Match = "abcdefghijkl"
   Groups = ["abcd", "bcd", "cd", "d", "efgh", "fgh", "gh", "h", "ijkl", "jkl", "kl", "l"]
;  false.

36. Named Capturing Groups Matching

Match pattern and extract named capturing groups using re_match_named//3 and lookup using re_group/3.

?- phrase(re_match_named("(?P<first>[a-z]+) ([a-z]+) (?P<last>[a-z]+)", Match, Named), "john middle doe"), re_group(Named, first, First).
   Match = "john middle doe"
   Named = [last-[d,o,e],first-[j,o,h,n]]
   First = "john"
;  false.

Multilingual & International Examples

37. International: French Accented Text

Match accented Latin characters.

?- phrase(re_match("café", Match), "café et croissant", Rest).
   Match = "café"
   Rest = " et croissant"
;  false.

38. International: Greek Characters & Quantifiers

Match Greek characters with Kleene plus quantifiers.

?- phrase(re_match("α+β+", Match), "αααβββ123", Rest).
   Match = "αααβββ"
   Rest = "123"
;  false.

39. International: Greek Character Range

Match characters using Unicode Greek range [α-ω].

?- phrase(re_match("[α-ω]+", Match), "αβγδεxyz", Rest).
   Match = "αβγδε"
   Rest = "xyz"
;  false.

40. International: Asian Character Set (Chinese Hanzi)

Match Chinese characters with named capturing groups.

?- phrase(re_match_named("(?P<greeting>你好)-(?P<target>世界)", Match, Named), "你好-世界").
   Match = "你好-世界"
   Named = [target-[世,界],greeting-[你,好]]
;  false.

41. International: Asian Character Set (Japanese Hiragana)

Match Japanese Hiragana characters.

?- phrase(re_match("こんにちは", Match), "こんにちは世界", Rest).
   Match = "こんにちは"
   Rest = "世界"
;  false.

42. International: Klingon Script PUA

Match Klingon script characters in Unicode Private Use Area (tlhIngan Hol).

?- phrase(re_match("", Match), " Hol", Rest).
   Match = ""
   Rest = " Hol"
;  false.

43. International: Emoji Characters & Quantifiers

Match Emoji characters with quantifiers.

?- phrase(re_match("🚀+😀+", Match), "🚀🚀😀😀😀!foo", Rest).
   Match = "🚀🚀😀😀😀"
   Rest = "!foo"
;  false.