Welcome to RegexApp Docs

RegexApp is a closed source Python package that is used to help individuals to generate Python regular expression pattern by using plain text.  RegexApp offers two licenses: and

Non-Commercial-Use License
Development Status ALPHA
Availability Online App by www.geekstrident.com
Installation N/A
Cost Free of Charge
Ad-Free With Ad
Test Solution N/A
Tech Support N/A
Integration N/A
Commercial-Use License
Development Status ALPHA
Availability Online or Offline App by CLIENT DEPLOYMENT or
Online App by PARTNER / THIRD-PARTY services
Installation Github or Offline-package
Cost Cost per Strategy
Ad-Free YES
Test Solution YES
Tech Support YES
Integration YES
(FYI: Helpful Videos )

Mitigating Human Error


Let's use typo error to demonstrate a process of mitigating this type of error.  Assuming user1 wants to create a regex pattern that can search multiple digits following by plus sign in text.  For example,

123+ 378173+

User1 really wants to create a below pattern

pattern = r"\d+\+"

Indeed, user1 accidentally creates a pattern without a second back flash

pattern = r"\d++"

Thus, a commit code without unit test might be a result of

>>> import re >>> >>> pattern = r"\d++" >>> >>> re.compile(pattern) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/Library/.../python3.9/re.py", line 252, in compile return _compile(pattern, flags) ... File "/Library/.../python3.9/sre_parse.py", line 671, in _parse raise source.error("multiple repeat", re.error: multiple repeat at position 3 >>>

Assuming RegexApp is available.  User1 needs to translate the requirements to a format that RegexApp can understand.  For this case, multiple digits are altered values.  RegexApp's digit keyword is an equivalent representation of this interpretation.  Plus sign is fixed value.  It's a regular text, just leave it as is.

If user pattern is created

digits()+

a result of generated pattern from RegexApp can be

pattern = r"\d+\+"
Therefore,as long as individuals understand well the given requirements and can build data pattern that RegexApp can interpret, the unintended action based errors could be reduced.

Let's use distraction to understand this type of error and find possible way to mitigate it.  Assuming user1 is given an assignment to create a regex pattern to match IPv4 address in text.

this is 1.1.1.1 IPv4 address.

User1 creates a pattern with testing

>>> >>> import re >>> >>> pattern = r" \d{1,3}(.\d{1,3}){3} " >>> >>> def test_pattern(pattern, test_data): ... for i, line in enumerate(test_data.splitlines(), 1): ... if line.strip(): ... match = re.search(pattern, line) ... if match: ... print(f'Match #{i}: {line}') ... >>> test_data = "this is 1.1.1.1 IPv4 address" >>> >>> test_pattern(pattern, test_data) Match #1: this is 1.1.1.1 IPv4 address >>>

Another day, user2 reuses user1's pattern.  After testing with new data, user2 sees unexpected outcome.  User2 forwards this issue user1.

>>> >>> import re >>> >>> pattern = r" \d{1,3}(.\d{1,3}){3} " >>> >>> test_data = """this is 1.1.1.1 IPv4 address current time is 10:20:30:456 PM""" >>> >>> test_pattern(pattern, test_data) Match #1: this is 1.1.1.1 IPv4 address Match #2: current time is 10:20:30:456 PM >>>

After studied problem, user1 explain

>>> >>> # distraction from personal matter combining >>> # with a few passed results from testing >>> # which leads to believe that the working >>> # assignment is ready. An Actual work should be >>> pattern = r" \d{1,3}(\.\d{1,3}){3} " >>> >>> test_data = """this is 1.1.1.1 IPv4 address current time is 10:20:30:456 PM""" >>> >>> test_pattern(pattern, test_data) Match #1: this is 1.1.1.1 IPv4 address >>>
Therefore, the unintended memory based error can be reduced if there is a good practice for reusing as many as possible verified solutions.

This type of error can be

  • Intended Rule Based Mistake
  • Intended Knowledge Based Mistake
  • Human Use Error
  • Latent Error
  • ...

and, the practical approach of software development process are

  • Quality Assurance
  • Collaboration
  • Risk Management
  • Security
  • Reliability
  • Consistency
  • Proficiency
  • Scalability
  • Extensibility
  • Portability
  • Continuous Improvement
  • ...

RegexApp needs to collaborate with other services to build high-quality software products.

Therefore, the intended error can be reduced if there is a workable strategy for development team.

Reusing Resource


The main purpose of RegexApp let individuals to reuse the verified solution as many as possible with confident so that individuals can produce the quality work and reduce waste or duplication.  For example, developer1 is given an assignment to create an IPv4 regular expression pattern.  Assuming developer1 creates IPv4 pattern with some testings,

>>> >>> import re >>> >>> pattern = "\d{1,3}(\.\d{1,3}){3}" >>> >>> re.search(f"\b{pattern}\b", "1.1.1.1") <re.Match object; span=(0, 7), match='1.1.1.1'> >>> >>> re.search(f"\b{pattern}\b", " 192.168.1.1 ") <re.Match object; span=(1, 12), match='192.168.1.1'> >>>

Developer1 thinks this pattern should work fine for matching or capturing IPv4 address, developer1 decides to implement it to code base.  After a while, developer1 receives feedback from end-users that IPv4 address pattern captures unexpected "2.3.5.320" value.  Developer1 performs RCA (i.e., Root Cause Analysis) and finds out a problem such as

The format of IPv4 address is <octet1>.<octet2>.<octet3>.<octet4> where octet1-4 must be from 0 to 255. ---------- While, "2.3.5.320" is software version which layout as, <major>.<minor>.<build>.<revision>

Technically, "\\d{1,3}(\\.\\d{1,3}){3}" should match IPv4 address and <major>.<minor>.<build>.<revision>.  Developer1 decides to resolve this problem to avoid any matching non-IPv4-address issue.

Step #1: Analyzing Octet
# octet ranging from 0 to 255 will break into 5 groups: 250-255, 200-249, 100-199, 10-99, and 0-9, # and its corresponding equivalent patterns are # ----------------------- # 250-255 => 25[0-5] # 200-249 => 2[0-4]\\d # 100-199 => 1\\d\\d # 10-99 => [1-9]\\d # 0-9 => \\d
Step #2: Creating Variables for Analyzing Cases
# 250-255 => 25[0-5] # 200-249 => 2[0-4]\\d # 100-199 => 1\\d\\d # 10-99 => [1-9]\\d # 0-9 => \\d p1 = "25[0-5]" # matching number 250 to 255 p2 = "2[0-4]\\d" # matching number 200 to 249 p3 = "1\\d\\d" # matching number 100 to 199 p4 = "[1-9]\\d" # matching number 10 to 99 p5 = "\\d" # matching number 0 to 9
Step #3: Simplifying Cases and Building Octet Pattern
>>> >>> p1 = "25[0-5]" # matching number 250 to 255 >>> p2 = "2[0-4]\\d" # matching number 200 to 249 >>> p3 = "1\\d\\d" # matching number 100 to 199 >>> p4 = "[1-9]\\d" # matching number 10 to 99 >>> p5 = "\\d" # matching number 0 to 9 >>> >>> # p4 and p5 can be simplify, so combine of p4 and p5 is >>> p4_combined_5 = "[1-9]?\\d" # should match number 0 to 99 >>> >>> # pattern of matching one octet from 0 to 255 is >>> octet_pat = f"({p1})|({p2})|({p3})|({p4_combined_5})" >>> >>> print(octet_pat) (25[0-5])|(2[0-4]\d)|(1\d\d)|([1-9]?\d) >>>
Step #4: Building IPv4 Address Pattern
>>> >>> # IPv4 address format : octet1.octet2.octet3.octet4 >>> # expressing in regex form : octet_pat\\.octet_pat\\.octet_pat\\.octet_pat >>> # or, to simplified regex form: (octet_pat)(\\.(octet_pat)){3} >>> >>> ipv4_addr_pat = "(%(octet_pat)s)(\\.(%(octet_pat)s)){3}" % dict(octet_pat=octet_pat) >>> >>> print(ipv4_addr_pat) ((25[0-5])|(2[0-4]\d)|(1\d\d)|([1-9]?\d))(\.((25[0-5])|(2[0-4]\d)|(1\d\d)|([1-9]?\d))){3} >>>
Step #5: Preparing Resources for Verification
def create_all_ipv4_addresses(): # This function should create four billion IPv4 addresses, # but it has too many addresses for testing. for octet1 in range(256): for octet2 in range(256): for octet3 in range(256): for octet4 in range(256): yield f"{octet1}.{octet2}.{octet3}.{octet4}" def create_ipv4_addresses(): # This function should create 1024 IPv4 addresses. # It should be good enough for testing. for octet in range(256): yield f"{octet}.1.1.1" yield f"1.{octet}.1.1" yield f"1.1.{octet}.1" yield f"1.1.1.{octet}" def create_non_ipv4_addresses(): # this function should create 4 non-IPv4 addresses. # It should be good enough for testing. yield "1.1.1.256" yield "1.1.256.1" yield "1.256.1.1" yield "256.1.1.1"
Step #6: Creating Test Function for Verifying IPv4 Address Pattern
def test_ipv4_address_pat(): p1 = "25[0-5]" # matching number 250 to 255 p2 = "2[0-4]\\d" # matching number 200 to 249 p3 = "1\\d\\d" # matching number 100 to 199 p4_combined_5 = "[1-9]?\\d" # should match number 0 to 99 # pattern of matching one octet from 0 to 255 is octet_pat = f"({p1})|({p2})|({p3})|({p4_combined_5})" ipv4_addr_pat = "(%(octet_pat)s)(\\.(%(octet_pat)s)){3}" % dict(octet_pat=octet_pat) pattern = f"{ipv4_addr_pat}$" # Verifying matching for addr in create_ipv4_addresses(): match = re.match(pattern, addr) assert match is not None # Verifying non-matched - that is negative testing. for non_addr in create_non_ipv4_addresses(): match = re.match(pattern, non_addr) assert match is None
Step #7: Executing Test
>>> >>> test_ipv4_address_pat() >>>

Assuming this quality rework MIGHT take developer1 one day of work or more.  If developer1 or team's developer1 doesn't have strategy for reusing this quality work, other developer might WASTE some work hours and MIGHT create other issue.  However, if RegexApp is available, developer1 can MANUALLY edit ipv4_address_with_validation solution if RegexApp is OFFLINE version.

Adding-Solution #1: Preparing Solution
ipv4_address_with_validation: &ipv4_address_with_validation # author: <unique author info> | <created_date>/<modified_data> description: a pattern to match exact IPv4 address. pattern: "((25[0-5])|(2[0-4]\\d)|(1\\d\\d)|([1-9]?\\d))(\\.((25[0-5])|(2[0-4]\\d)|(1\\d\\d)|([1-9]?\\d))){3}" positive_test: [ "127.0.0.1", "192.168.0.1", "255.255.255.255" ] negative_test: [ "127.1111.0.1", "127.256.1.1", "256.1.1.1", "127.0 0.1" ] # create alias ipv4_addr_with_validation: *ipv4_address_with_validation ipv4_addr_w_validation: *ipv4_address_with_validation
Adding-Solution #2: Appending Solution

Depending on OS and RegexApp name, assuming OS is macOS and app name is RegexPro.  Manually appending solution to this "~/.geekstrident/regexpro/user_references.yaml" file.  For example,

% user1@userpc /Users/user1 % ls -l ~/.geekstrident/regexpro total 8 -rw-r--r-- 1 user1 staff 2004 Jul 12 17:14 user_references.yaml user1@user1pc /Users/user1 %
Adding-Solution #3: Restarting WebRegex App and Verifying User Custom Keywords
RegexApp Reusing Resource Demo1
Adding-Solution #4: Executing Some Tests for Confirmation
RegexApp Reusing Resource Demo1
Adding-Solution #5: Informing Development Teams or Other Groups

As a result, work productivity will improve if more verified solutions are reused.


RegexApp lets individuals to reuse their own test data to build a GENERIC solution.  RegexApp builder provides five features: , , , , and .

Therefore, the unintended memory based error can be reduced if there is a good practice for reusing as many as possible verified solutions.

RegexApp Builder - Differential

Differential feature lets end-user to build generic snippet or regex pattern based on multiple different data where format of data should be a combination of <UNCHANGED-TEXT> and <CHANGED-TEXT>. Assuming end-user wants to capture color value in this data set where differential pattern of this data set is
<UNCHANGED-TEXT> <CHANGED-TEXT> <UNCHANGED-TEXT> ... <CHANGED-TEXT> <UNCHANGED-TEXT> <CHANGED-TEXT> ... Where UNCHANGED-TEXT MUST BE a text. CHANGED-TEXT can be a text or empty string.

For example, assuming end-user wants to capture color value in this data set

this is red pencil this is black pencil this is pencil
Iteration #1: Preparing Multiple Different Test Data

Copy each data to and paste to Test-Data of Builder - Differential.  RegexApp should create

this is red pencil <<separator>> this is black pencil <<separator>> this is pencil

or just manually edit <<separator>> on top to let RegexApp to interpret data set as multiple line-test-data.

<<separator>> this is red pencil this is black pencil this is pencil
Iteration #2: Building Solution From Test Data and Testing
The Modification checkbox next to combo box must be unchecked.  The generated snippet should be
# Non-commercial use: generated by WebRegex v.0.1.12 (geekstrident.com) # Created Date: 2023-09-09 15:37 ################################ start() this is letters(var_v0, or_empty) pencil end()
and the generated pattern should be
# Non-commercial use: generated by RegexApp v.0.4.10 (geekstrident.com) # Created Date: 2023-09-09 15:37 ################################ pattern = r"^this is\s*(?P<v0>([a-zA-Z]+)|) pencil$"
and the test result should be
##### block #1 ##### this is red pencil {'v0': 'red'} ##### block #2 ##### this is black pencil {'v0': 'black'} ##### block #3 ##### this is pencil {'v0': ''}
Iteration #3: Modifying Generated Snippet and Testing
Check Modification checkbox to reuse modifying snippet and perform modifying
change default generated "v0" variable to "color" variable ---------- ## from start() this is letters(var_v0, or_empty) pencil end() ## to start() this is letters(var_color, or_empty) pencil end()
The new generated pattern after modification should be
# Non-commercial use: generated by RegexApp v.0.4.10 (geekstrident.com) # Created Date: 2023-09-09 16:08 ################################ pattern = r"^this is\s*(?P<color>([a-zA-Z]+)|) pencil$"
and the new test result after modification should be
##### block #1 ##### this is red pencil {'color': 'red'} ##### block #2 ##### this is black pencil {'color': 'black'} ##### block #3 ##### this is pencil {'color': ''}
RegexApp Builder - Category

Category feature lets end-user to build generic snippet or regex pattern based on single data where format of data should be
<TEXT><SEPARATOR><VALUE> <TEXT><SEPARATOR><VALUE> .... <TEXT><SEPARATOR> <VALUE> <TEXT><SEPARATOR> <VALUE> .... <TEXT> <SEPARATOR> <VALUE> <TEXT> <SEPARATOR> <VALUE> .... Where TEXT MUST BE a text. VALUE can be a text or empty string. SEPARATOR is often punctuation mark such as ":" symbol.

For example, assuming end-user wants to capture meats, fruits, and drinks values in this data set

meats: chicken, pork fruits: mango, peach drinks: coca, pesi
Iteration #1: Preparing Test Data
1) Paste test data in Test-Data of Builder - Category 2) Determine separator and entry it in separator text box. In this case, take no action because separator is the default separator, i.e., : symbol. 3) Determ total number of category and entry it in category-count text box. In this case, total-category-count is 2.  Enter 2 in category-count text box.
Iteration #2: Building Solution From Test Data and Testing
The Modification checkbox next to combo box must be unchecked.  The generated snippet should be
# Non-commercial use: generated by WebRegex v.0.1.12 (geekstrident.com) # Created Date: 2023-09-09 17:15 ################################ meats: mixed_phrase(var_meats) fruits: mixed_phrase(var_fruits) drinks: mixed_phrase(var_drinks)
The generated pattern should be
# Non-commercial use: generated by RegexApp v.0.4.10 (geekstrident.com) # Created Date: 2023-09-09 17:15 ################################ pattern = r"meats: (?P<meats>[\x21-\x7e]*[a-zA-Z0-9][\x21-\x7e]*( [\x21-\x7e]*[a-zA-Z0-9][\x21-\x7e]*)+) +fruits: (?P<fruits>[\x21-\x7e]*[a-zA-Z0-9][\x21-\x7e]*( [\x21-\x7e]*[a-zA-Z0-9][\x21-\x7e]*)+)(\r\n|\r|\n)drinks: (?P<drinks>[\x21-\x7e]*[a-zA-Z0-9][\x21-\x7e]*( [\x21-\x7e]*[a-zA-Z0-9][\x21-\x7e]*)+)"
The test result should be
################################ meats: chicken, pork fruits: mango, peach drinks: coca, pesi {'meats': 'chicken, pork', 'fruits': 'mango, peach', 'drinks': 'coca, pesi'}
Iteration #3: Modifying Generated Snippet and Testing If Necessary
1) Check Modification checkbox 2) Modify and Retest if necessary
RegexApp Builder - Iteration

Iteration feature helps end-users to understand how generic snippet or regex pattern get constructed.  It uses test data to generate interaction protocol.  Individuals need to interact with interaction protocol to build a solution.

NOTE: Interaction protocol is ONLY HELPFUL and USABLE for FREE STYLE feature.  It is not recommended to use this feature to build solution.  Furthermore, Iteration feature LIMITS to work with single line of test data.

Iteration #1: Building Interaction Protocol

Assuming test data is

today temperature . . 78 fahrenheit

Click build button on Builder - Iteration, WebRegex should generate this interaction protocol

# Non-commercial use: generated by WebRegex v.0.1.12 (geekstrident.com) # Created Date: 2023-09-09 23:38 ################################ capture() keep() action(): letters(var=v0, value=today) letters(var=v1, value=temperature) punct(var=v2, value=.) punct(var=v3, value=.) digits(var=v4, value=78) letters(var=v5, value=fahrenheit)
Iteration #2: Modifying Interaction Protocol

Interaction protocol has two group of keywords: Operating Keywords and Editing Keywords

Operating Keywords: capture() keep() action() Syntax: capture(#, #, #:#) keep(#, #, #:#) action(#-split-<separator>) action(#,#-join) action(#:#-join) action(var_name1,var_name2,..,var_name_n-join)
Editing Keywords: e.g., letters(var=v0, value=today) letters(var=v1, value=temperature) ... Syntax: <keyword>(cvar=<var_name>, value=<value>) <keyword>(Cvar=<var_name>, value=<value>) <keyword>(kvar=<var_name>, value=<value>) <keyword>(Kvar=<var_name>, value=<value>) Notes: capitol letter "C" or "K" should allow to match or to capture empty value.
Iteration #2-1: Modifying Interaction Protocol - Assigning Capturing Variable

Assuming end-user wants to capture temperature value and temperature unit

1) Ensure that modification checkbox is checked.  If not, check it. 2) Locate the position of capturing variables, in this case, digits(var=v4, value=78) letters(var=v5, value=Fahrenheit) 3) Apply capturing 3.a) Using operating keyword method capture(4,5) capture(4-as-temperature, 5-as-unit) should be supported in BETA version. 3.b) Using editing keyword method ...  digits(cvar=temperature, value=78) letters(cvar=unit, value=fahrenheit)

The new generated snippet should be

# Non-commercial use: generated by WebRegex v.0.1.12 (geekstrident.com) # Created Date: 2023-09-10 00:24 ################################ today temperature . . digits(var_temperature) letters(var_unit)

The new generated pattern should be

# Non-commercial use: generated by WebRegex v.0.1.12 (geekstrident.com) # Created Date: 2023-09-10 00:24 ################################ pattern = r"today temperature \. \. (?P<temperature>\d+) (?P<unit>[a-zA-Z]+)"
Iteration #2-2: Modifying Interaction Protocol - Applying Matching

Assuming a first word of test data can be either

today temperature ... yesterday temperature ... tomorrow temperature ...

Use keep(0) or kvar=v0 to build matching.  The new generated snippet should be

# Non-commercial use: generated by WebRegex v.0.1.12 (geekstrident.com) # Created Date: 2023-09-10 00:36 ################################ letters() temperature . . digits(var_temperature) letters(var_unit)

The new generated pattern should be

# Non-commercial use: generated by WebRegex v.0.1.12 (geekstrident.com) # Created Date: 2023-09-10 00:36 ################################ pattern = r"[a-zA-Z]+ temperature \. \. (?P<temperature>\d+) (?P<unit>[a-zA-Z]+)"

However, if first word of test data can be a value or empty, use Kvar=v0 to solve it

Assuming test data can be --------- today temperature . . 78 fahrenheit or yesterday temperature . . 78 fahrenheit or tomorrow temperature . . 78 fahrenheit or temperature . . 78 fahrenheit --------- # Non-commercial use: generated by WebRegex v.0.1.12 (geekstrident.com) # Created Date: 2023-09-10 00:42 ################################ capture() keep() action(): letters(Kvar=v0, value=today) letters(var=v1, value=temperature) punct(var=v2, value=.) punct(var=v3, value=.) digits(cvar=temperature, value=78) letters(cvar=unit, value=fahrenheit) --------- # Non-commercial use: generated by WebRegex v.0.1.12 (geekstrident.com) # Created Date: 2023-09-10 00:42 ################################ letters(or_empty)zero_or_spaces()temperature . . digits(var_temperature) letters(var_unit) --------- # Non-commercial use: generated by WebRegex v.0.1.12 (geekstrident.com) # Created Date: 2023-09-10 00:42 ################################ pattern = r"(([a-zA-Z]+)|) *temperature \. \. (?P<temperature>\d+) (?P<unit>[a-zA-Z]+)"
Iteration #2-3: Modifying Interaction Protocol - Joining Variables

Assuming end-user wants to join temperature and unit variables into one variable and name it as temperature_unit

Step 1: Applying action(temperature,unit-join) to perform join

# Non-commercial use: generated by WebRegex v.0.1.12 (geekstrident.com) # Created Date: 2023-09-10 01:00 ################################ capture() keep() action(temperature, unit-join): letters(Kvar=v0, value=today) letters(var=v1, value=temperature) punct(var=v2, value=.) punct(var=v3, value=.) digits(cvar=temperature, value=78) letters(cvar=unit, value=Fahrenheit) ---------- # Non-commercial use: generated by WebRegex v.0.1.12 (geekstrident.com) # Created Date: 2023-09-10 01:00 ################################ letters(or_empty)zero_or_spaces()temperature . . 78 Fahrenheit

Step 2: Applying cvar=temperature_unit to perform capturing

# Non-commercial use: generated by WebRegex v.0.1.12 (geekstrident.com) # Created Date: 2023-09-10 01:02 ################################ capture() keep() action(): letters(Kvar=v0, value=today) letters(var=v1, value=temperature) punct(var=v2, value=.) punct(var=v3, value=.) mixed_phrase(cvar=temperature_unit, value=78 Fahrenheit) ---------- # Non-commercial use: generated by WebRegex v.0.1.12 (geekstrident.com) # Created Date: 2023-09-10 01:02 ################################ letters(or_empty)zero_or_spaces()temperature . . mixed_phrase(var_temperature_unit)
Iteration #2-4: Modifying Interaction Protocol - Splitting Variable

Assuming test data is

flag=123

and the generated interaction protocol is

# Non-commercial use: generated by WebRegex v.0.1.12 (geekstrident.com) # Created Date: 2023-09-10 01:11 ################################ capture() keep() action(): mixed_word(var=v0, value=flag=123)

Assuming end-user wants to capture 123 value and store in flag variable

Step 1: Performing split operation

==>> change action() to action(0-split-=) # Non-commercial use: generated by WebRegex v.0.1.12 (geekstrident.com) # Created Date: 2023-09-10 01:11 ################################ capture() keep() action(0-split-=): mixed_word(var=v0, value=flag=123) ---------- ==>> after click build button, it should generate below interaction protocol # Non-commercial use: generated by WebRegex v.0.1.12 (geekstrident.com) # Created Date: 2023-09-10 01:11 ################################ capture() keep() action(): letters(var=v00, value=flag)punct(var=v01, value==)digits(var=v02, value=123)

Step 1: Performing capture operation

==>> change var=v02 to cvar-flag # Non-commercial use: generated by WebRegex v.0.1.12 (geekstrident.com) # Created Date: 2023-09-10 01:14 ################################ capture() keep() action(): letters(var=v00, value=flag)punct(var=v01, value==)digits(cvar=flag, value=123) ---------- ==>> after click build button, it should generate below interaction protocol # Non-commercial use: generated by WebRegex v.0.1.12 (geekstrident.com) # Created Date: 2023-09-10 01:14 ################################ capture() keep() action(): letters(var=v00, value=flag)punct(var=v01, value==)digits(cvar=flag, value=123) and generated snippet should be # Non-commercial use: generated by WebRegex v.0.1.12 (geekstrident.com) # Created Date: 2023-09-10 01:14 ################################ flag=digits(var_flag)
RegexApp Builder - Free Style

SHOULD BE AVAILABLE in BETA VERSION

RegexApp Builder - Designing

SHOULD BE AVAILABLE in BETA VERSION

Low Learning Curve

RegexApp employs principle of least effort to boost individuals to quickly recognize problem and confidently build solution.  Builder features are generated GENERIC solution which is based on human analogy expression combining generic decision making selection.  For example,

Problem ------- Create regular expression pattern to match "c" character and "1" character. Individual Interpretation ------------------------- Human analog expression of "c" character is "c" letter. Human analog expression of "1" character is "1" digit. Human analog expression of alphabet numeric is any character from "0" to "9", "A" to Z", or "a" to "z" +++++ Therefore, the most closed common matching between letter and digit is pattern of alphabet numeric. In other words, alphabet numeric is superset of letter and digit, or letter and digit are the subset of alphabet numeric. ============================== Problem ------- Create regular expression pattern to match "c" character and "." character. Individual Interpretation ------------------------- Human analog expression of "c" character is "c" letter. Human analog expression of "." character is "." punctuation. Human analog expression of the printable character of standard ASCII characters (a.k.a, graph) is any character from "!" to "/" "0" to "9" ":" to "@" "A" to "Z" "[" to "`" "a" to "z" "{" to "~" +++++ Therefore, the most closet common matching between letter and punctuation is pattern of graph. In other words, graph is the superset of letter and punctuation, or letter and punctuation are the subset of graph.
RegexApp Text Correlation - Singular Form

RegexApp Text Correlation

Furthermore, RegexApp provide intuitive method to play with data to produce the solution.  For example, assuming end-user is given an assignment to parse output of command line that contains interface name, flag value, interface status, interface info, and mtu value.

RegexApp - Analyzing Test Data

Step 1: Reformatting Data to General Human Readable Form
Test Data --------- en0: flags=9100<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500 WHERE interface_name = en0 flag_value = 9100 interface_status = UP interface_info = BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST mtu_value = 1500 =========================== Should be EQUIVALENT to GENERAL FORM interface_name: flags=flag_value<interface_status,interface_info> mtu mtu_value
Step 2: Separating Any Combining Fields
General form ------------ interface_name: flags=flag_value<interface_status,interface_info> mtu mtu_value interface_name: should separate as interface_name : flags=flag_value<interface_status,interface_info> should separate as flags = flag_value < interface_status , interface_info > New general form should be -------------------------- interface_name : flags = flag_value < interface_status , interface_info > mtu mtu_value
Step 3: Creating New Test Data by Substitution
New general form ---------------- interface_name : flags = flag_value < interface_status , interface_info > mtu mtu_value WHERE interface_name = en0 flag_value = 9100 interface_status = UP interface_info = BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST mtu_value = 1500 New test data should be ----------------------- en0 : flags = 9100 < UP , BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST > mtu 1500
Step 4: Preparing Multi Test Data For Builder - Differential Feature
New test data ------------- en0 : flags = 9100 < UP , BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST > mtu 1500 Duplicate new test data and modify interface_name, flag_value, interface_status interface_info, mtu_value becoming different values Modified multi test data should be ---------------------------------- en0 : flags = 9100 < UP , BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST > mtu 1500 en1 : flags = 9200 < uP , bROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST > mtu 1501
Step 5: Building Solution and Testing
Modified multi test data ------------------------ <<separator>> en0 : flags = 9100 < UP , BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST > mtu 1500 en1 : flags = 9200 < uP , bROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST > mtu 1501 Generated Snippet is -------------------- # Non-commercial use: generated by WebRegex v.0.1.12 (geekstrident.com) # Created Date: 2023-09-11 17:40 ################################ start() word(var_v0) : flags = digits(var_v1) < letters(var_v2) , mixed_word(var_v3) > mtu digits(var_v4) end() Test Result is ============== ##### block #1 ##### en0 : flags = 9100 < UP , BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST > mtu 1500 {'v0': 'en0', 'v1': '9100', 'v2': 'UP', 'v3': 'BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST', 'v4': '1500'} ##### block #2 ##### en1 : flags = 9200 < uP , bROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST > mtu 1501 {'v0': 'en1', 'v1': '9200', 'v2': 'uP', 'v3': 'bROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST', 'v4': '1501'}
Step 6: Modifying Appropriate Variable Names
Generated Snippet ----------------- start() word(var_v0) : flags = digits(var_v1) < letters(var_v2) , mixed_word(var_v3) > mtu digits(var_v4) end() Replacing default variables to v0 to interface_name v1 to flag_value v2 to interface_status v3 to interface_info v4 to mtu_value Modified snippet should be -------------------------- start() word(var_interface_name) : flags = digits(var_flag_value) < letters(var_interface_status) , mixed_word(var_interface_info) > mtu digits(var_mtu_value) end() Test Result is ============== ##### block #1 ##### en0 : flags = 9100 < UP , BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST > mtu 1500 {'interface_name': 'en0', 'flag_value': '9100', 'interface_status': 'UP', 'interface_info': 'BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST', 'mtu_value': '1500'} ##### block #2 ##### en1 : flags = 9200 < uP , bROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST > mtu 1501 {'interface_name': 'en1', 'flag_value': '9200', 'interface_status': 'uP', 'interface_info': 'bROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST', 'mtu_value': '1501'}
Step 7: Restoring Generated Snippet to Original Format and Testing
Modified Snippet (or user snippet) is ------------------------------------- start() word(var_interface_name) : flags = digits(var_flag_value) < letters(var_interface_status) , mixed_word(var_interface_info) > mtu digits(var_mtu_value) end() word(var_interface_name) : needs to change back to word(var_interface_name): flags = digits(var_flag_value) < letters(var_interface_status) , mixed_word(var_interface_info) > needs to change back to flags=digits(var_flag_value)<letters(var_interface_status),mixed_word(var_interface_info)> New Modified Snippet is ----------------------- start() word(var_interface_name): flags=digits(var_flag_value)<letters(var_interface_status),mixed_word(var_interface_info)> mtu digits(var_mtu_value) end() Test Result is ============== ################################ en0: flags=9100<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500 {'interface_name': 'en0', 'flag_value': '9100', 'interface_status': 'UP', 'interface_info': 'BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST', 'mtu_value': '1500'}
Step 8: Intuitively Communicating with Other

Assuming below generated snippet and generated pattern are final solution

User Snippet (i.e. modified snippet) ------------------------------------ start() word(var_interface_name): flags=digits(var_flag_value)<letters(var_interface_status),mixed_word(var_interface_info)> mtu digits(var_mtu_value) end() Generated Pattern is -------------------- pattern = r"^(?P<interface_name>[a-zA-Z][a-zA-Z0-9]*): flags=(?P<flag_value>\d+)<(?P<interface_status>[a-zA-Z]+),(?P<interface_info>[\x21-\x7e]*[a-zA-Z0-9][\x21-\x7e]*)> mtu (?P<mtu_value>\d+)$"

However, reviewer might disagree below test result because reviewer thinks that interface_status should be "UP", "DOWN", or "ERROR", but it CAN NOT be broadcast.

Other Test Data is ------------------ ap1: flags=9500<BROADCAST,SIMPLEX,MULTICAST> mtu 1500 User Snippet is --------------- start() word(var_interface_name): flags=digits(var_flag_value)<letters(var_interface_status),mixed_word(var_interface_info)> mtu digits(var_mtu_value) end() Test Result is ============== ap1: flags=9500<BROADCAST,SIMPLEX,MULTICAST> mtu 1500 {'interface_name': 'ap1', 'flag_value': '9500', 'interface_status': 'BROADCAST', 'interface_info': 'SIMPLEX,MULTICAST', 'mtu_value': '1500'}

If end-user uses generated pattern to discuss the unexpected result with data owner, they might need more time to find the root cause.

Generated Pattern is -------------------- pattern = r"^(?P<interface_name>[a-zA-Z][a-zA-Z0-9]*): flags=(?P<flag_value>\d+)<(?P<interface_status>[a-zA-Z]+),(?P<interface_info>[\x21-\x7e]*[a-zA-Z0-9][\x21-\x7e]*)> mtu (?P<mtu_value>\d+)$"

However, if end-user uses general form or generated snippet to discuss the unexpected result with reviewer or data owner,

General Form is --------------- interface_name: flags=flag_value<interface_status,interface_info> mtu mtu_value User Snippet is --------------- start() word(var_interface_name): flags=digits(var_flag_value)<letters(var_interface_status),mixed_word(var_interface_info)> mtu digits(var_mtu_value) end()

data owner or reviewer might quickly make feedback such as

Feedback -------- interface_name: flags=flag_value<{interface_status, or empty}{, or empty}interface_info> mtu mtu_value where interface_status can be UP, DOWN, ERROR, or empty string comma next to interface_status only presents if UP, DOWN, or ERROR presents.

End-user can improve solution by reworking snippet to deliver expected result such as

!!!!! {interface_status, or empty} interface_status can be UP, DOWN, ERROR, or empty string ===== that means interface_status needs to match the exact value UP, DOWN, or ERROR. Therefore, letters(var_interface_status) should be replaced to data(var_interface_status, UP, DOWN, ERROR, or_empty) !!!!! {, or empty} comma next to interface_status only presents if UP, DOWN, or ERROR presents ===== To make this case happens, 1) convert comma text to comma symbol 2) add or_empty argument {, or empty} in plain text should be equivalent to symbol(name=comma, or_empty) The new user snippet should be ------------------------------ start() word(var_interface_name): flags=digits(var_flag_value)<data(var_interface_status, UP, DOWN, ERROR, or_empty)symbol(name=comma, or_empty)mixed_word(var_interface_info)> mtu digits(var_mtu_value) end() Test result is ============== ##### block #1 ##### en0: flags=9100<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500 {'interface_name': 'en0', 'flag_value': '9100', 'interface_status': 'UP', 'interface_info': 'BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST', 'mtu_value': '1500'} ##### block #2 ##### ap1: flags=9500<BROADCAST,SIMPLEX,MULTICAST> mtu 1500 {'interface_name': 'ap1', 'flag_value': '9500', 'interface_status': '', 'interface_info': 'BROADCAST,SIMPLEX,MULTICAST', 'mtu_value': '1500'}

Furthermore, data owner or reviewer adds additional feedback such as,

Feedback -------- interface_name can be a word of letters a word of letters with digits a word of letters-letters with digits a word of letters with digits.digits ...

End-user continues to improve solution such as

Feedback -------- interface_name can be a word of letters a word of letters with digits a word of letters-letters with digits a word of letters with digits.digits ... ===== mixed_word might be fixed these above interface_name requirements. Therefore, word(var_interface_name) should be replaced to mixed_word(var_interface_name)
Step 9: Submitting Finally Result For Reviewing
Multi Test Data --------------- en0: flags=9100<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500 ap1: flags=9500<BROADCAST,SIMPLEX,MULTICAST> mtu 1500 User Snippet ------------ start() mixed_word(var_interface_name): flags=digits(var_flag_value)<data(var_interface_status, UP, DOWN, ERROR, or_empty)symbol(name=comma, or_empty)mixed_word(var_interface_info)> mtu digits(var_mtu_value) end() Generated Pattern ----------------- # Non-commercial use: generated by RegexApp v.0.4.10 (geekstrident.com) # Created Date: 2023-09-11 22:37 ################################ pattern = r"^(?P<interface_name>[\x21-\x7e]*[a-zA-Z0-9][\x21-\x7e]*): flags=(?P<flag_value>\d+)<(?P<interface_status>(UP|DOWN|ERROR)|)(,|)(?P<interface_info>[\x21-\x7e]*[a-zA-Z0-9][\x21-\x7e]*)> mtu (?P<mtu_value>\d+)$" Test Result =========== ##### block #1 ##### en0: flags=9100<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500 {'interface_name': 'en0', 'flag_value': '9100', 'interface_status': 'UP', 'interface_info': 'BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST', 'mtu_value': '1500'} ##### block #2 ##### ap1: flags=9500<BROADCAST,SIMPLEX,MULTICAST> mtu 1500 {'interface_name': 'ap1', 'flag_value': '9500', 'interface_status': '', 'interface_info': 'BROADCAST,SIMPLEX,MULTICAST', 'mtu_value': '1500'}

The main purpose of RegexApp application is to simplify a process of creating regular expression pattern to improve code quality.  Most features are designed to solve specific problem relating to human error, wasting resources, or complex training.  Experience individuals with solid regular expression problem-solving knowledge who rely too much on RegexApp MUST BE a result of lowering regular expression creativity over time.

There are three types of keywords: , , and . These keywords associate with to enhance matching or capturing capacity.

Reserved Keywords

There are four reversed keywords: , , , and .
start
an indicator keyword to generate regex pattern to match at the beginning of string.  Its keyword arguments are: space, spaces, ws, whitespace, or whitespaces.

Usage
start() or start(ws) start(space) or start(spaces) start(whitespace) or start(whitespaces)

Example
start() should generate "^"
start(space) should generate "^ *"
start(spaces) should generate "^ +"
start(ws) should generate r"^\s*"
start(whitespace) should generate r"^\s*"
start(whitespaces) should generate r"^\s+"
end
an indicator keyword to generate regex pattern to match at the end of string.  Its keyword arguments are: space, spaces, ws, whitespace, or whitespaces.

Usage
end() or end(ws) end(space) or end(spaces) end(whitespace) or end(whitespaces)

Example
end() should generate "$"
end(space) should generate " *$"
end(spaces) should generate " +$"
end(ws) should generate r"\s*$"
end(whitespace) should generate r"\s*$"
end(whitespaces) should generate r"\s+$"
data
an matching or capturing keyword to generate regex pattern to match or to capture raw data.  Its keyword arguments should be similar to system keyword arguments.

Usage
data(<raw_data>) data(var_<name>, <raw_data>, <other_arguments>)

Example
data(..) data(var_v1, ++>passed, word_bound_right) should generate r"\.\. (?P<v1>(\+\+>passed)\b)"
>>> >>> import re >>> test_data = ".. ++>passed" >>> # assuming generated pattern is >>> pattern = r"\.\. (?P<v1>(\+\+>passed)" >>> match = re.search(pattern, test_data) >>> print(match) <re.Match object; span=(0, 12), match='.. ++>passed'> >>> print(match.groupdict()) {'v1': '++>passed'} >>>
end
an matching or capturing keyword to generate regex pattern to match or to capture predefined symbols.  Its keyword arguments should be similar to system keyword arguments.

Usage
symbol(name=<symbol_name>) symbol(var_<name>, name=<symbol_name>, <other_arguments>)

Example
start() symbol(name=dot, 5_occurrences) symbol(name=hyphen, at_least_3_occurrence) end() should generate r"^\.{5} +-{3,}$"
The generated pattern should match this "..... ----------" data.
The generated pattern should not match this "........ ----------" data.

System Keywords

These keywords are created by App owner or integration partner and stored in system_references.yaml and it can be found in package installation directory.  Keywords MUST NOT DUPLICATE reserved keywords.  System keywords MUST BE a file based because Python package installation process SHOULD make it to become READONLY keywords (i.e., unmodified keywords).  Checkout these examples: , , , , , .
Usage
<keyword>(var_<name>, <other_data,...>, or_empty, or_<other_keywords>, <keyword_arguments>)
Example #1
digits() is a format of
<keyword>()
which should match at least one numeric.
Its generated pattern is r"\d+".
Example #2
digits(N/A) is a format of
<keyword>(<other_data,...>)
which should match at least one numeric or N/A data.
Its generated pattern is r"\d+|N/A".
Example #3
digits(var_v1, N/A) is a format of
<keyword>(var_<name>, <other_data,...>)
which should capture at least one numeric or N/A data, and then store in v1 variable.
Its generated pattern is r"(?P<v1>\d+|N/A)".
Example #4
digits(var_v1, or_empty) is a format of
<keyword>(var_<name>, or_empty)
which should capture at least one numeric or empty data and then store in v1 variable.
Its generated pattern is r"(?P<v1>\d+|)".
>>> import re >>> >>> # start() Food: word(var_food, or_empty) Total: digits(var_total, N/A) end() >>> # Assuming pattern is generated from above user data pattern >>> pattern = r"^Food:\s*(?P<food>[a-zA-Z][a-zA-Z0-9]*|) +Total: (?P<total>\d+|N/A)$" >>> >>> test_data = """ ... Food: Mango Total: 159 ... Food: Total: N/A ... """.strip() >>> >>> for line in test_data.splitlines(): ... match = re.search(pattern, line) ... if match: ... print(match.groupdict()) ... {'food': 'Mango', 'total': '159'} {'food': '', 'total': 'N/A'} >>>
Example #5
ipv4_addr(var_addr, or_mac_addr) is a format of
<keyword>(var_<name>, or_<other_keyword>)
which should capture either IPv4 address or MAC address, and then store in addr variable.
Its generated pattern is r"^Address: (?P<addr>\d{1,3}([.]\d{1,3}){3}|([0-9a-fA-F]{2}([: -][0-9a-fA-F]{2}){5})) *$".
>>> # start() Address: ipv4_addr(var_addr, or_mac_addr) end(space) >>> # Assuming pattern is generated from above user data pattern >>> pattern = r"^Address: (?P<addr>\d{1,3}([.]\d{1,3}){3}|([0-9a-fA-F]{2}([: -][0-9a-fA-F]{2}){5})) *$" >>> >>> test_data = """ ... Address: 192.168.1.1 ... Address: AA:11:BB:22:CC:33 ... """.strip() >>> >>> import re >>> >>> for line in test_data.splitlines(): ... match = re.search(pattern, line) ... if match: ... print(match.groupdict()) ... {'addr': '192.168.1.1'} {'addr': 'AA:11:BB:22:CC:33'} >>>
Example #6
letters(var_v1, 5_occurrence) is a format of
<keyword>(var_<name>, <keyword_arguments>)
which should match at least one numeric.
Its generated pattern is r"(?P<v1>[a-zA-Z]{5})".

User Keywords

These keywords are created by users and stored in ~/.geekstrident/regexpro/user_references.yaml file on deployed system.  Keywords MUST NOT DUPLICATE reserved and system keywords.  Future version should provide an option to let users to store or to access user keyword by using database.  The usage of user keywords is similar to the usage of system keywords

Keyword Arguments

Categories: , , , , , , , , and .

var_<name>
encapsulate keyword pattern with (?P<name>...).  It should let regex store matching data to variable.
word(var_v1) should generate r"(?P<v1>[a-zA-Z][a-zA-Z0-9]*)" and store matching word to v1 variable.
or_empty
join keyword pattern and empty string with | separator, and then encapsulate result with parenthesis, i.e., (...|). It should let regex match zero or pattern.
word(or_empty) should generate r"([a-zA-Z][a-zA-Z0-9]*|)" that should match a word or an empty string.

or_<other_keyword>
join keyword pattern and other-keyword pattern with | separator, and then encapsulate result with parenthesis, i.e., (...|...). It should let regex match either keyword pattern or other keyword pattern.
time(or_number, format4) should generate r"(\d{2}:\d{2})|((\d+)?[.]?\d+)" that should match a number or time value of format 4 HH:MM.

or_<datum>
<datum>
join keyword pattern and datum with | separator.
Case 1: no enclosed parenthesis if data is singular form, i.e.,...|data1|data2|data_n.
digits(or_n/a, or_null, or_none) should generate r"(\d+)|n/a|null|none".
digits(n/a, null, none) should generate r"(\d+)|n/a|null|none".
Case 2: with enclosed parenthesis if data is plural form, i.e., (...|(data 1)|data2|data_n).
digits(or_n/a, or_not applicable) should generate r"((\d+)|n/a|(not applicable))".
digits(n/a, not applicable) should generate r"((\d+)|n/a|(not applicable))".

or_repeat_k_space
or_k_space
join ( {k}) and keyword pattern with | separator, and then encapsulate result with parenthesis, i.e., (( {k})|...).
word(var_v1, or_repeat_5_space) should generate r"(?P<v1>( {5})|([a-zA-Z][a-zA-Z0-9]*))".
word(var_v1, or_5_space) should generate r"(?P<v1>( {5})|([a-zA-Z][a-zA-Z0-9]*))".

or_repeat_m_n_space
join ( {m,n}) and keyword pattern with | separator, and then encapsulate result with parenthesis, i.e., (( {m,n})|...).
word(var_v1, or_repeat_2_5_space) should generate r"(?P<v1>( {2,5})|([a-zA-Z][a-zA-Z0-9]*))".

or_repeat__n_space
or_at_most_n_space
join ( {,n}) and keyword pattern with | separator, and then encapsulate result with parenthesis, i.e., (( {,n})|...).
word(var_v1, or_repeat__5_space) should generate r"(?P<v1>( {,5})|([a-zA-Z][a-zA-Z0-9]*))".
word(var_v1, or_at_most_5_space) should generate r"(?P<v1>( {,5})|([a-zA-Z][a-zA-Z0-9]*))".

or_repeat_m__space
or_at_least_m_space
join ( {m,}) and keyword pattern with | separator, and then encapsulate result with parenthesis, i.e., (( {m,})|...).
word(var_v1, or_repeat_2__space) should generate r"(?P<v1>( {2,})|([a-zA-Z][a-zA-Z0-9]*))".
word(var_v1, or_at_least_5_space) should generate r"(?P<v1>( {2,})|([a-zA-Z][a-zA-Z0-9]*))".

or_either_repeat_k_space
or_either_k_space
join ( {k}) and keyword pattern with | separator, and then encapsulate result with parenthesis, i.e., (( {k})| *... *).
word(var_v1, or_either_repeat_5_space) should generate r"(?P<v1>( {5})|( *[a-zA-Z][a-zA-Z0-9]* *))".
word(var_v1, or_either_5_space) should generate r"(?P<v1>( {5})|( *[a-zA-Z][a-zA-Z0-9]* *))".

or_either_repeat_m_n_space
join ( {m,n}) and keyword pattern with | separator, and then encapsulate result with parenthesis, i.e., (( {m,n})| *... *).
word(var_v1, or_either_repeat_2_5_space) should generate r"(?P<v1>( {2,5})|( *[a-zA-Z][a-zA-Z0-9]* *))".

or_either_repeat__n_space
or_either_at_most_n_space
join ( {,n}) and keyword pattern with | separator, and then encapsulate result with parenthesis, i.e., (( {,n})| *... *).
word(var_v1, or_either_repeat__5_space) should generate r"(?P<v1>( {,5})|( *[a-zA-Z][a-zA-Z0-9]* *))".
word(var_v1, or_either_at_most_5_space) should generate r"(?P<v1>( {,5})|( *[a-zA-Z][a-zA-Z0-9]* *))".

or_either_repeat_m__space
or_either_at_least_m_space
join ( {m,}) and keyword pattern with | separator, and then encapsulate result with parenthesis, i.e., (( {m,})| *... *).
word(var_v1, or_either_repeat_2__space) should generate r"(?P<v1>( {2,})|( *[a-zA-Z][a-zA-Z0-9]* *))".
word(var_v1, or_either_at_least_5_space) should generate r"(?P<v1>( {2,})|( *[a-zA-Z][a-zA-Z0-9]* *))".
repeat_k
append {k} to keyword pattern which transform to match exact k-time.
letter(var_v1, repetition_5) should generate r"(?P<v1>[a-zA-Z]{5})".

repeat_m _n
append {m,n} to keyword pattern which transform to match at least m-time and at most n-time.
letter(var_v1, repetition_2_5) should generate r"(?P<v1>[a-zA-Z]{2,5})".

repeat__n
append {,n} to keyword pattern which transform to match at most n-time.
letter(var_v1, repetition__5) should generate r"(?P<v1>[a-zA-Z]{,5})".

repeat_m_
append {m,} to keyword pattern which transform to match at least m-time.
letter(var_v1, repetition_2_) should generate r"(?P<v1>[a-zA-Z]{2,})".
k_occurrence
if k = 0, append ? to keyword pattern which transform to match zero or one matching.
if k = 1, is to match itself.
if k > 1, append {k} to keyword pattern which transform to match k-times.
letter(var_v1, 0_occurrence) should generate r"(?P<v1>[a-zA-Z]?)".
letter(var_v1, 1_occurrence) should generate r"(?P<v1>[a-zA-Z])".
letter(var_v1, 5_occurrence) should generate r"(?P<v1>[a-zA-Z]{5})".

0_or_1_occurrence
append ? to keyword pattern which transform to match zero or one.
letter(var_v1, 0_or_1_occurrence) should generate r"(?P<v1>[a-zA-Z]?)".

k_or_more_occurrence
if k = 0, append * to keyword pattern which transform to match zero or more matching.
if k = 1, append + to keyword pattern which transform to match at least one matching.
if k > 1, append {k,} to keyword pattern which transform to match at least k-times.
letter(var_v1, 0_or_more_occurrence) should generate r"(?P<v1>[a-zA-Z]*)".
letter(var_v1, 1_or_more_occurrence) should generate r"(?P<v1>[a-zA-Z]+)".
letter(var_v1, 3_or_more_occurrence) should generate r"(?P<v1>[a-zA-Z]{3,})".

at_least_m_occurrence
if m = 0, append * to keyword pattern which transform to match zero or more matching.
if m >= 1, append {m,} to keyword pattern which transform to match at least m-times.
letter(var_v1, at_least_0_occurrence) should generate r"(?P<v1>[a-zA-Z]*)".
letter(var_v1, at_least_3_occurrence) should generate r"(?P<v1>[a-zA-Z]{3,})".

at_most_n_occurrence
if n = 0, append ? to keyword pattern which transform to match zero or one matching.
if n >= 1, append {,n} to keyword pattern which transform to match at most n-times.
letter(var_v1, at_most_0_occurrence) should generate r"(?P<v1>[a-zA-Z]?)".
letter(var_v1, at_most_8_occurrence) should generate r"(?P<v1>[a-zA-Z]{,8})".
k_phrase_occurrence
k_group_occurrence
if k = 0, append ( ...)? or ( +...)? to keyword pattern which transform to match one or two matching.
if k = 1, append ( ...) or ( +...) to keyword pattern which transform to match exact two matching.
if k > 1, append ( ...){k,} or ( +...){k,} to keyword pattern which transform to match exact (k + 1) matching.
word(0_phrase_occurrence) should generate r"[a-zA-Z][a-zA-Z0-9]*( [a-zA-Z][a-zA-Z0-9]*)?".
word(0_group_occurrence) should generate r"[a-zA-Z][a-zA-Z0-9]*( +[a-zA-Z][a-zA-Z0-9]*)?".
word(1_phrase_occurrence) should generate r"[a-zA-Z][a-zA-Z0-9]*( [a-zA-Z][a-zA-Z0-9]*)".
word(1_group_occurrence) should generate r"[a-zA-Z][a-zA-Z0-9]*( +[a-zA-Z][a-zA-Z0-9]*)".
word(5_phrase_occurrence) should generate r"[a-zA-Z][a-zA-Z0-9]*( [a-zA-Z][a-zA-Z0-9]*){5}".
word(5_group_occurrence) should generate r"[a-zA-Z][a-zA-Z0-9]*( +[a-zA-Z][a-zA-Z0-9]*){5}".

0_or_1_phrase_occurrence
0_or_1_group_occurrence
append ( ...)? or ( +...)? to keyword pattern which transform to match one or two matching.
word(0_or_1_phrase_occurrence) should generate r"[a-zA-Z][a-zA-Z0-9]*( [a-zA-Z][a-zA-Z0-9]*)?".
word(0_or_1_group_occurrence) should generate r"[a-zA-Z][a-zA-Z0-9]*( +[a-zA-Z][a-zA-Z0-9]*)?".

k_or_more_phrase_occurrence
k_or_more_group_occurrence
if k = 0, append ( ...)* or ( +...)* to keyword pattern which transform to match at least one matching.
if k = 1, append ( ...)+ or ( +...)+ to keyword pattern which transform to match at least two matching.
if k > 1, append ( ...){k,} or ( +...){k,} to keyword pattern which transform to match at least (k + 1) matching.
word(0_or_more_phrase_occurrence) should generate r"[a-zA-Z][a-zA-Z0-9]*( [a-zA-Z][a-zA-Z0-9]*)*".
word(0_or_more_group_occurrence) should generate r"[a-zA-Z][a-zA-Z0-9]*( +[a-zA-Z][a-zA-Z0-9]*)*".
word(1_or_more_phrase_occurrence) should generate r"[a-zA-Z][a-zA-Z0-9]*( [a-zA-Z][a-zA-Z0-9]*)+".
word(1_or_more_group_occurrence) should generate r"[a-zA-Z][a-zA-Z0-9]*( +[a-zA-Z][a-zA-Z0-9]*)+".
word(5_or_more_phrase_occurrence) should generate r"[a-zA-Z][a-zA-Z0-9]*( [a-zA-Z][a-zA-Z0-9]*){5,}".
word(5_or_more_group_occurrence) should generate r"[a-zA-Z][a-zA-Z0-9]*( +[a-zA-Z][a-zA-Z0-9]*){5,}".

at_least_m_phrase_occurrence
at_least_m_group_occurrence
if m = 0, append ( ...)* or ( +...)* to keyword pattern which transform to match at least one matching.
if m >= 1, append ( ...){m,} or ( +...){m,} to keyword pattern which transform to match at least (m + 1) matching.
word(at_least_0_phrase_occurrence) should generate r"[a-zA-Z][a-zA-Z0-9]*( [a-zA-Z][a-zA-Z0-9]*)*".
word(at_least_0_group_occurrence) should generate r"[a-zA-Z][a-zA-Z0-9]*( +[a-zA-Z][a-zA-Z0-9]*)*".
word(at_least_5_phrase_occurrence) should generate r"[a-zA-Z][a-zA-Z0-9]*( [a-zA-Z][a-zA-Z0-9]*){5,}".
word(at_least_5_group_occurrence) should generate r"[a-zA-Z][a-zA-Z0-9]*( +[a-zA-Z][a-zA-Z0-9]*){5,}".

at_most_n_phrase_occurrence
at_most_n_group_occurrence
if n = 0, append ( ...)? or ( +...)? to keyword pattern which transform to match at most one or two matching.
if n >= 1, append ( ...){,n} or ( +...){,n} to keyword pattern which transform to match at most (n + 1) matching.
word(at_most_0_phrase_occurrence) should generate r"[a-zA-Z][a-zA-Z0-9]*( [a-zA-Z][a-zA-Z0-9]*)?".
word(at_most_0_group_occurrence) should generate r"[a-zA-Z][a-zA-Z0-9]*( +[a-zA-Z][a-zA-Z0-9]*)?".
word(at_most_5_phrase_occurrence) should generate r"[a-zA-Z][a-zA-Z0-9]*( [a-zA-Z][a-zA-Z0-9]*){,5}".
word(at_most_5_group_occurrence) should generate r"[a-zA-Z][a-zA-Z0-9]*( +[a-zA-Z][a-zA-Z0-9]*){,5}".
word_bound_left
prepend \b to the beginning of keyword pattern.  It should let regex perform word bound on left matching.
word(word_bound_left) should generate r"\b[a-zA-Z][a-zA-Z0-9]*".

word_bound_right
append \b to the end of keyword pattern.  It should let regex perform word bound on right matching.
word(word_bound_right) should generate r"[a-zA-Z][a-zA-Z0-9]*\b".

word_bound
enclose \b around keyword pattern.  It should let regex perform word bound on matching.
word(word_bound) should generate r"\b[a-zA-Z][a-zA-Z0-9]*\b".
head
prepend ^ to keyword pattern which inform regex engine that pattern should start at the beginning of string.
word(head) should generate r"^[a-zA-Z][a-zA-Z0-9]*".

head_ws
head_whitespace
prepend ^\\s* to keyword pattern which inform regex engine that pattern should start at the beginning of string with zero or some whitespaces.
word(head_whitespace) should generate r"^\s*[a-zA-Z][a-zA-Z0-9]*".

head_ws_plus
head_whitespaces
head_whitespace_plus
prepend ^\\s+ to keyword pattern which inform regex engine that pattern should start at the beginning of string with some whitespaces.
word(head_whitespaces) should generate r"^\s+[a-zA-Z][a-zA-Z0-9]*".

head_space
prepend ^ * to keyword pattern which inform regex engine that pattern should start at the beginning of string with zero or some blank-space.
word(head_space) should generate r"^ *[a-zA-Z][a-zA-Z0-9]*".

head_spaces
head_space_plus
prepend ^ + to keyword pattern which inform regex engine that pattern should start at the beginning of string with some blank-space.
word(head_spaces) should generate r"^ +[a-zA-Z][a-zA-Z0-9]*".

head_just_ws
head_just_whitespace
prepend \\s* to keyword pattern which transform to match zero or some whitespaces and then pattern.
word(head_just_whitespace) should generate r"\s*[a-zA-Z][a-zA-Z0-9]*".

head_just_ws_plus
head_just_whitespaces
head_just_whitespace_plus
prepend \\s+ to keyword pattern which transform to match some whitespaces and then pattern.
word(head_just_whitespaces) should generate r"\s+[a-zA-Z][a-zA-Z0-9]*".

head_just_space
prepend * to keyword pattern which transform to match zero or some blank-space and then pattern.
word(head_just_space) should generate r" *[a-zA-Z][a-zA-Z0-9]*".

head_just_spaces
head_just_space_plus
prepend + to keyword pattern which transform to match some blank-space and then pattern.
word(head_just_spaces) should generate r" +[a-zA-Z][a-zA-Z0-9]*".
tail
append $ to keyword pattern which inform regex engine that stop matching after seeing pattern.
word(tail) should generate r"[a-zA-Z][a-zA-Z0-9]*$".

tail_ws
tail_whitespace
append \\s*$ to keyword pattern which inform regex engine that stop matching after seeing pattern and zero or some whitespaces.
word(tail_whitespace) should generate r"[a-zA-Z][a-zA-Z0-9]*\s*$".

tail_ws_plus
tail_whitespaces
tail_whitespace_plus
prepend \\s+$ to keyword pattern which inform regex engine that stop matching after seeing pattern and some whitespaces.
word(tail_whitespaces) should generate r"[a-zA-Z][a-zA-Z0-9]*\s+$".

tail_space
prepend *$ to keyword pattern which inform regex engine that stop matching after seeing pattern and zero or some blank-space.
word(tail_space) should generate r"[a-zA-Z][a-zA-Z0-9]* *$".

tail_spaces
tail_space_plus
append +$ to keyword pattern which inform regex engine that stop matching after seeing pattern and some blank-space.
word(tail_spaces) should generate r"[a-zA-Z][a-zA-Z0-9]* +$".

tail_just_ws
tail_just_whitespace
append \\s* to keyword pattern which transform to match pattern and then zero or some whitespaces.
word(tail_just_whitespace) should generate r"[a-zA-Z][a-zA-Z0-9]*\s*".

tail_just_ws_plus
tail_just_whitespaces
tail_just_whitespace_plus
append \\s+ to keyword pattern which transform to match pattern and then some whitespaces
word(tail_just_whitespaces) should generate r"[a-zA-Z][a-zA-Z0-9]*\s+".

tail_just_space
append * to keyword pattern which transform to match pattern and zero or some blank-space.
word(tail_just_space) should generate r"[a-zA-Z][a-zA-Z0-9]* *".

tail_just_spaces
tail_just_space_plus
append + to keyword pattern which transform to match pattern and then some blank-space.
word(tail_just_spaces) should generate r"[a-zA-Z][a-zA-Z0-9]* +".
?
To Be Announced
letter(var_v1, ?) should generate r"(?P<v1>[a-zA-Z]?)".

*
To Be Announced
letter(var_v1, *) should generate r"(?P<v1>[a-zA-Z]*)".

+
To Be Announced
letter(var_v1, +) should generate r"(?P<v1>[a-zA-Z]+)".

{k}
To Be Announced
letter(var_v1, {0) should generate r"(?P<v1>[a-zA-Z]?)".
letter(var_v1, {1) should generate r"(?P<v1>[a-zA-Z])".
letter(var_v1, {5) should generate r"(?P<v1>[a-zA-Z]{5})".

{m,n}
To Be Announced
letter(var_v1, {,5) should generate r"(?P<v1>[a-zA-Z]{,5})".
letter(var_v1, {2,) should generate r"(?P<v1>[a-zA-Z]{2,})".
letter(var_v1, {2,5) should generate r"(?P<v1>[a-zA-Z]{2,5})".

phrase?
group?
To Be Announced
letters(var_v1, phrase?) should generate r"(?P<v1>[a-zA-Z]+( [a-zA-Z]+)?)".
letters(var_v1, group?) should generate r"(?P<v1>[a-zA-Z]+( +[a-zA-Z]+)?)".

phrase*
group*
To Be Announced
letters(var_v1, phrase*) should generate r"(?P<v1>[a-zA-Z]+( [a-zA-Z]+)*)".
letters(var_v1, group*) should generate r"(?P<v1>[a-zA-Z]+( +[a-zA-Z]+)*)".

phrase+
group+
To Be Announced
letters(var_v1, phrase+) should generate r"(?P<v1>[a-zA-Z]+( [a-zA-Z]+)+)".
letters(var_v1, group+) should generate r"(?P<v1>[a-zA-Z]+( +[a-zA-Z]+)+)".

phrase{k}
group{k}
To Be Announced
letters(var_v1, phrase{0}) should generate r"(?P<v1>[a-zA-Z]+( [a-zA-Z]+)?)".
letters(var_v1, group{0}) should generate r"(?P<v1>[a-zA-Z]+( +[a-zA-Z]+)?)".
letters(var_v1, phrase{1}) should generate r"(?P<v1>[a-zA-Z]+( [a-zA-Z]+))".
letters(var_v1, group{1}) should generate r"(?P<v1>[a-zA-Z]+( +[a-zA-Z]+))".
letters(var_v1, phrase{5}) should generate r"(?P<v1>[a-zA-Z]+( [a-zA-Z]+){5})".
letters(var_v1, group{5}) should generate r"(?P<v1>[a-zA-Z]+( +[a-zA-Z]+){5})".

phrase{m,n}
group{m,n}
To Be Announced
letters(var_v1, phrase{2,}) should generate r"(?P<v1>[a-zA-Z]+( [a-zA-Z]+){2,})".
letters(var_v1, group{2,}) should generate r"(?P<v1>[a-zA-Z]+( +[a-zA-Z]+){2,})".
letters(var_v1, phrase{,5}) should generate r"(?P<v1>[a-zA-Z]+( [a-zA-Z]+){,5})".
letters(var_v1, group{,5}) should generate r"(?P<v1>[a-zA-Z]+( +[a-zA-Z]+){,5})".
letters(var_v1, phrase{2,5}) should generate r"(?P<v1>[a-zA-Z]+( [a-zA-Z]+){2,5})".
letters(var_v1, group{2,5}) should generate r"(?P<v1>[a-zA-Z]+( +[a-zA-Z]+){2,5})".

or_space?
or_ws?
or_whitespace?
or_either_space?
or_either_ws?
or_either_whitespace?
To Be Announced
letters(var_v1, or_space?) should generate r"(?P<v1>( ?)|([a-zA-Z]+))".
letters(var_v1, or_whitespace?) should generate r"(?P<v1>(\s?)|([a-zA-Z]+))".
letters(var_v1, or_either_space?) should generate r"(?P<v1>( ?)|( *[a-zA-Z]+ *))".
letters(var_v1, or_either_whitespace?) should generate r"(?P<v1>(\s?)|( *[a-zA-Z]+ *))".

or_space*
or_ws*
or_whitespace*
or_either_space*
or_either_ws*
or_either_whitespace*
To Be Announced
letters(var_v1, or_space*) should generate r"(?P<v1>( *)|([a-zA-Z]+))".
letters(var_v1, or_whitespace*) should generate r"(?P<v1>(\s*)|([a-zA-Z]+))".
letters(var_v1, or_either_space*) should generate r"(?P<v1>( *)|( *[a-zA-Z]+ *))".
letters(var_v1, or_either_whitespace*) should generate r"(?P<v1>(\s*)|( *[a-zA-Z]+ *))".

or_space+
or_ws+
or_whitespace+
or_either_space+
or_either_ws+
or_either_whitespace+
To Be Announced
letters(var_v1, or_space+) should generate r"(?P<v1>( +)|([a-zA-Z]+))".
letters(var_v1, or_whitespace+) should generate r"(?P<v1>(\s+)|([a-zA-Z]+))".
letters(var_v1, or_either_space+) should generate r"(?P<v1>( +)|( *[a-zA-Z]+ *))".
letters(var_v1, or_either_whitespace+) should generate r"(?P<v1>(\s+)|( *[a-zA-Z]+ *))".

or_space{k}
or_ws{k}
or_whitespace{k}
or_either_space{k}
or_either_ws{k}
or_either_whitespace{k}
To Be Announced
letters(var_v1, or_space{5}) should generate r"(?P<v1>( {5})|([a-zA-Z]+))".
letters(var_v1, or_whitespace{5}) should generate r"(?P<v1>(\s{5})|([a-zA-Z]+))".
letters(var_v1, or_either_space{5}) should generate r"(?P<v1>( {5})|( *[a-zA-Z]+ *))".
letters(var_v1, or_either_whitespace{5}) should generate r"(?P<v1>(\s{5})|( *[a-zA-Z]+ *))".

or_space{m,n}
or_ws{m,n}
or_whitespace{m,n}
or_either_space{m,n}
or_either_ws{m,n}
or_either_whitespace{m,n}
To Be Announced
letters(var_v1, or_space{2,}) should generate r"(?P<v1>( {2,})|([a-zA-Z]+))".
letters(var_v1, or_whitespace{2,}) should generate r"(?P<v1>(\s{2,})|([a-zA-Z]+))".
letters(var_v1, or_either_space{2,}) should generate r"(?P<v1>( {2,})|( *[a-zA-Z]+ *))".
letters(var_v1, or_either_whitespace{2,}) should generate r"(?P<v1>(\s{2,})|( *[a-zA-Z]+ *))".
letters(var_v1, or_space{,5}) should generate r"(?P<v1>( {,5})|([a-zA-Z]+))".
letters(var_v1, or_whitespace{,5}) should generate r"(?P<v1>(\s{,5})|([a-zA-Z]+))".
letters(var_v1, or_either_space{,5}) should generate r"(?P<v1>( {,5})|( *[a-zA-Z]+ *))".
letters(var_v1, or_either_whitespace{,5}) should generate r"(?P<v1>(\s{,5})|( *[a-zA-Z]+ *))".
letters(var_v1, or_space{2,5}) should generate r"(?P<v1>( {2,5})|([a-zA-Z]+))".
letters(var_v1, or_whitespace{2,5}) should generate r"(?P<v1>(\s{2,5})|([a-zA-Z]+))".
letters(var_v1, or_either_space{2,5}) should generate r"(?P<v1>( {2,5})|( *[a-zA-Z]+ *))".
letters(var_v1, or_either_whitespace{2,5}) should generate r"(?P<v1>(\s{2,5})|( *[a-zA-Z]+ *))".

RegexApp Workflow

Restriction