Using rxmatch() and rxsub() with PCRE regex

Introduction

This article was originally written for Iguana 5 and may contain out of date references.

This article shows how to use the string.rxmatch() and string.rxsub() functions with PCRE regex, these functions are the equivalent of string.gmatch() and string.gsub(), but using PCRE regex instead of the simpler Lua pattern matching. There are also some (hopefully) helpful PCRE regex examples, including some useful features (that are not available with Lua pattern matching).

For information on the differences between PCRE regex and Perl and POSIX regex, see these PCRE reference links: Perl Differences and Differences from POSIX regex.

All regex patterns used in this article are listed on the PCRE Samples page, including links to any examples on the rxmatch() and rxsub() pages.

To find out more you can follow the More Information links below or do a quick web search (“PCRE”, “PCRE regex”, “PCRE tutorial”).

Tip: I found the Regex 101 online tester very helpful when creating/testing the expressions on this page. The Regex Buddy application (Windows only) also comes highly recommended, though it is not free. And you can google to find many other regex testers.

Also the regexper page is helpful for visualising regex queries as Railroad Diagrams (EBNF Syntax Diagrams), for example the regex “/PID(\|[^|]*){5}(Sm[iy]the?)\b/” looks like this:

Using rxmatch() [top]

Tip: It is very easy to adapt PHP examples for Iguana, rxmatch() corresponds to preg_grep (and to a lesser extent preg_match).

  1. This first example is very simple, it just loops through a string and prints each word. As you can see there is slight difference: the first is that PCRE uses the “\” escape character where Lua uses “%”, so PCRE uses “\w” and Lua use “%w” to match all letters (word characters). There is a difference in the “word characters” matched: Lua matches alphanumeric characters, but PCRE matches alphanumeric plus “_” underscore.
    Note: The escape “\” character must be escaped as “\\” in Lua strings, or you can use square brackets as string delimeters “[<string value>]” without escaping.

       -- Iterate over all the words from string s, printing one per line:
       
       -- using gmatch
       s = "hello world from Lua"
       for w in s:gmatch("%w+") do
          print(w)
       end
       
       -- using rxmatch
       s = "hello world from Lua and PCRE"
      for w in s:rxmatch("\\w+") do         -- the \ character must be escaped as \\ in Lua strings
      -- for w in s:rxmatch([\w+]) do       -- alternatively you can use the [] syntax without escaping
          print(w)
       end 
    
  2. This example uses captures “(<captured value>)” to collect all key value pairs and write them into a Lua table. As you can see the only difference is that PCRE uses the “\” escape character where Lua uses “%”.

       -- Collect all pairs key=value from the given string into a table:
       
       -- using gmatch
       t = {}
       s = "from=world, to=Lua"
       for k, v in s:gmatch("(%w+)=(%w+)") do
          t[k] = v
       end
        
       -- using rxmatch
       t = {}
       s = "from=world, to=Lua"
       for k, v in s:rxmatch("(\\w+)=(\\w+)") do    -- the \ character must be escaped as \\ in Lua strings
       --for k, v in s:rxmatch([(\w+)=(\w+)]) do    -- alternatively you can use the [] syntax without escaping
          t[k] = v
       end
    
  3. You can use captures to find duplicated words:
      -- find duplicate words
       
       -- using gmatch   
       local s = "hello hello world world"
       for k, v in s:gmatch("(%w+)(%s+%1)") do
          trace(k, v)
       end
       
       -- using rxmatch  
       local s = "hello hello world world"
       for k, v in s:rxmatch("(\\b\\w+\\b)(\\W+\\1)") do
          trace(k, v)
       end
  4. And now for a trick with regex that you can’t do with Lua patterns, finding a word (or pattern) in a string that is not followed by another word. To achieve this we will use a PCRE “lookaround” subpattern.
    To find “hello” only when it is not followed by “world”, use a negative lookahead:

      -- not possible with gmatch()
       t = {}
       local s = "hello everyone my name is ..."
       for k in s:rxmatch("(hello)(?!.*world)") do -- negative lookahead - PCRE only
          trace(k)
       end
  5. Capture quoted text in a string, using captures allows us to write one regex that works for single (‘) and double (“) quotes.
       -- capture text in quotes
       
       local s = 'She said "Hello everyone"'
       for k in s:rxmatch([[("[^"]+")]]) do        -- capture text including quotes
          trace(k)
       end
       --> "Hello everyone"
       
       local s = 'She said "Hello everyone"'
       for k in s:rxmatch([["([^"]+)"]]) do        -- capture text excluding the quotes
          trace(k)
       end
       --> Hello everyone
     
       local s = [[She said "Don't wait up"]]
       for k in s:rxmatch([[(['"][^'"]+['"])]]) do -- capture text including quotes = FAIL stops at (matches) single quote
          trace(k)
       end
       --> "Don' (stops incorrectly on single quote)
     
       local s = [[She said "Don't wait up"]]
       for k in s:rxmatch([[((["'])[^\2]+\2)]]) do -- capture text including quotes = SUCCESS using capture \2 to identify 
          trace(k)                                 -- which type of opening quote is used
       end
       --> "Don't wait up"
    
       local s = [[She said "Don't wait up"]]
       for k,v in s:rxmatch([[(["'])([^\1]+)\1]]) do -- capture text excluding the quotes = SUCCESS using capture \1 to identify 
          trace(k,v)                                 -- which type of opening quote is used
       end
       --> Don't wait up (NOTE: this is the second return "v")
  6. Capture text inside brackets or other delimiters:
       -- capture text inside delimiters like brackets, etc.
       
       local s = "Hello to the world (and everyone)"
       for k in s:rxmatch('(\\([^)]+\\))') do        -- capture text including brackets (or substitute other delimiters)
          trace(k)
       end
       -->(and everyone)
    
       local s = "Hello to the world (and everyone)"
       for k in s:rxmatch('\\(([^)]+)\\)') do        -- just capture text (NOT including brackets)
          trace(k)
       end
       -->and everyone
  7. Extract HTML or XML tags:
       -- extract HTML or XML tags
       
       local s = '<a href="#hello_world">Hello world link</a>'
       for k in s:rxmatch('(<[^>]+>)') do              -- extract HTML tags
          trace(k)
       end
    
       local s = [[<?xml version="1.0"?>
       <patients>
          <patient id="123">
             <first-name>John</first-name>
             <last-name>Smith</last-name>
          </patient>
       </patients>]]
       for k in s:rxmatch('(<[^>]+>)') do              -- extract XML tags
          trace(k)
       end
    
       local s = [[<?xml version="1.0"?>
       <patients>
          <patient id = "123">
             <first-name>John</first-name>
             <last-name>Smith</last-name>
          </patient>
       </patients>]]
       for k in s:rxmatch('(<[^>]+\\sid\\b[^>]+>)') do -- only extract XML tags containing an id attribute
          trace(k)
       end
  8. White-listing and black-listing are useful both useful techniques.
    1. White-listing is simple with rxmatch() but next to impossible with gmatch():
         -- white-list
      
         -- using rxmatch  
      
         -- match single word
         local s = "Hello hello world I was here world"
         for k in s:rxmatch('(\\bhello\\b)', 'i') do       -- \b (word boundaries) to only match whole words
            trace(k)                                       -- 'i' (3rd param) for case insensitive match
         end
      
         -- extend to matching a list
         local s = "Hello hello world I was here world"
         for k in s:rxmatch('\\b(hello|world)\\b', 'i') do -- move the \b (word boundaries) outside the the capture group
            trace(k)
         end
      
         -- simply extend the list as required
         local s = "Hello to the world, Mars, Venus and the Universe"
         for k in s:rxmatch('\\b(hello|world|mars|venus|universe)\\b', 'i') do 
            trace(k) 
         end
      
         -- using gmatch - cannot be done easily
      
         -- matching a single word/phrase is easy
         local s = "Hello hello world I was here"
         for k in s:lower():gmatch('(hello)') do           -- using lower() for  for case insensitive match
            trace(k)
         end
      
         -- unfortunately Lua will also match partial words as well
         local s = "Hello to the worldwide web"
         for k in s:lower():gmatch('(hello)') do           -- matches "world" in "worldwide"
            trace(k)
         end
         -- NOTE: This excludes the partial match but it misses the first hello
         for k in s:lower():gmatch('%W(hello)%W') do 
            trace(k)
         end
         
         -- also Lua patterns do not support "|" (OR) so you cannot match members in a list
         local s = "Hello hello|world world I was here"
         for k in s:lower():gmatch('(hello|world)') do     -- matches string "hello|world"
            trace(k)
         end
      
         -- though you could loop through a white-list stored in table
         local s = "Hello hello world I was here world"
         local wlist = {'hello', 'world'}
         for i=1,#wlist do  
            trace(wlist[i])
            for k in s:lower():gmatch(wlist[i]) do         -- using lower() for case insensitive match
               trace(k)
            end
         end
    2. A black-list is also simple with rxmatch() but we are not even going to try it gmatch():
         -- black-list
         
         -- first lets exclude a single word
         local s = "Hello hello world I was here world"
         for k in s:rxmatch([[\bhello\b(*SKIP)(*FAIL)|(\w+)]], 'i') do
            trace(k) 
         end
      
         -- then exclude words in a list
         for k in s:rxmatch([[\bhello\b(*SKIP)(*FAIL)|\bworld\b(*SKIP)(*FAIL)|\w+]], 'i') do
            trace(k) 
         end
         -- Compact Version: place \b and (*SKIP)(*FAIL) outside a non-capturing group
         for k in s:rxmatch([[\b(?:hello|world)\b(*SKIP)(*FAIL)|\w+]], 'i') do
            trace(k) 
         end
      
      
  9. Here are some examples of unicode matching.
    1. First a trivial example to help understand matching a specific unicode grapheme (compound character) like “à”:
      Note: The unicode “à” is composed of two code points (symbols): U+0061 (a) followed by U+0300 (grave accent).

         -- demonstrate that "à" is composed of two unicode code points
         string.byte('à',1,2)       --> 195,160 = decimal values of U+0061 and U+0300
      
         -- using gmatch  
         local s = "à"
         for k in s:gmatch(".") do  --> trace('\195') - matches the first code point (195)
            trace(k)                --> trace('\160') - then the 2nd
         end
         for k in s:gmatch("..") do --> trace('à') - matches the whole grapheme (2 code points)
            trace(k)
         end
         for k in s:gmatch("à") do  --> trivially matches "à"
            trace(k)
         end
            
         -- using rxmatch  
         local s = "à"
         for k in s:rxmatch(".") do  --> trace('\195') - matches the first code point (195)
            trace(k)                 --> trace('\160') - then the 2nd
         end
         for k in s:rxmatch("..") do --> trace('à') - matches the whole grapheme (2 code points)
            trace(k)
         end
         for k in s:rxmatch("à") do  --> trivially matches "à"
            trace(k)
         end
      
         -- using rxmatch Unicode specific features 
         -- NOTE: you must include 'u' (unicode) as the 3rd parameter
         local s = "à"
         for k in s:rxmatch([[\X]], 'u') do    -- trace('à') - match the grapheme using "\X" (the unicode equivalent of ".")
            trace(k)
         end
         for k in s:rxmatch([[\p{L}]], 'u') do -- trace('à') - match any unicode letter grapheme 
            trace(k)
         end
         for k in s:rxmatch([[\p{Lu}]], 'u') do -- trace('à') - match any unicode lower case letter grapheme 
            trace(k)
         end
    2. Now lets look at matching multiple unicode graphemes in a string, this can only be done with PCRE (rxmatch).
         -- matching unicode graphemes
         
         -- using rxmatch
         local s = "Ábcd éfgh ©copyright"
         local cnt = 0
         for k in s:rxmatch([[\X]], 'u') do     -- match all unicode graphemes "\X"
            trace(k)
            cnt = cnt + 1
         end
         trace(cnt)                             --> cnt = 20 matches each letter (the unicode graphemes "Áé©" each count as a single letter)
      
         cnt = 0
         for k in s:rxmatch([[\p{L}]], 'u') do  -- match all unicode letter graphemes "\p{L}"
            trace(k)
            cnt = cnt + 1
         end
         trace(cnt)                             --> cnt = 17 two spaces and the "©" are not matched
      
         cnt = 0
         for k in s:rxmatch([[\p{Ll}]], 'u') do -- match lowercase unicode letter graphemes "\p{Ll}"
            trace(k)
            cnt = cnt + 1
         end
         trace(cnt)                             --> cnt = 16 spaces "Á" and the "©" are not matched
      
         cnt = 0
         for k in s:rxmatch([[\p{Lu}]], 'u') do -- match uppercase unicode letter graphemes "\p{Lu}"
            trace(k)
            cnt = cnt + 1
         end
         trace(cnt)                             --> cnt = 1 only "Á" is matched
         
         cnt = 0
         for k in s:rxmatch([[\p{S}]], 'u') do  -- match unicode symbol graphemes "\p{S}"
            trace(k)
            cnt = cnt + 1
         end
         trace(cnt)                             --> cnt = 1 only "©" is matched
    3. Detect if a string contains graphemes for a specified language, using unicode scripts like \p{Greek} or \p{Cyrillic}, etc.
         -- matching unicode scripts like \p{Greek} or \p{Cyrillic}, etc.
         
         -- using rxmatch
         local s = "Hello world in Greek Γειά σου Κόσμε (from google translate)"
         local cnt = 0
         for k in s:rxmatch([[\p{Greek}]], 'u') do -- match all Greek graphemes
            trace(k)
            cnt = cnt + 1
         end
         trace(cnt)                                --> cnt = 12 Greek letters
      
         local s = "Hello world in Greek Γειά σου Κόσμε (from google translate)"
         local cnt = 0
         for k in s:rxmatch([[\P{Greek}]], 'u') do -- match all NON Greek graphemes
            trace(k)
            cnt = cnt + 1
         end
         trace(cnt)                                --> cnt = 47 NON Greek letters

Using rxsub() [top]

Tip: It is very easy to adapt PHP examples for Iguana, rxsub() corresponds to preg_filter and preg_replace.

  1. The first two example is very simple, replace a word or a phrase. As you can see (in this case) there is no difference between the string.gsub() and string.rxsub() syntax.
    1. Replace a word:
         -- match and replace a word
      
         -- using gsub   
         local s = "hello world my name is ..."
         x = s:gsub( "world", "everyone")           
         --> hello everyone my name is ... 
      
         -- using rxsub
         local s = "hello world my name is ..."
         x = s:rxsub( "world", "everyone")
         --> hello everyone my name is ...
    2. Replace a phrase:
         -- match and replace a phrase
      
         -- using gsub
         local s = "hello everyone my name is ... "
         x = s:gsub( "hello everyone", "Hello World") 
         --> Hello World my name is ...
      
         -- using rxsub   
         local s = "hello everyone my name is ... "
         x = s:rxsub( "hello everyone", "Hello World") 
         --> Hello World my name is ...
  2. This next example shows how to remove duplicate space or whitespace characters.
    Note: Space is just a space ” “, whitespace includes all space characters (like space, tab, newline, carriage return, vertical tab).

       -- remove duplicate spaces
    
       -- using gsub   
       local s = "hello world  I     was  here"
       x = s:gsub(" +", " ")                         -- replace multiple spaces with a single space
       --> hello world I was here
       local s = "hello world    I \t was \r\n here"
       x = s:gsub("%s+", " ")                        -- replace *any* multiple whitespace characters with a single space 
       --> hello world I was here
       
       -- using rxsub   
       local s = "hello world  I    was     here"
       x = s:rxsub(" +", " ")                        -- replace multiple spaces with a single space
       --> hello world I was here
       local s = "hello world    I \t was \r\n here"
       x = s:rxsub("\\s+", " ")                      -- replace *any* multiple whitespace characters with a single space 
       --> hello world I was here
  3. This example removes multiple spaces or whitespace characters before a fullstop (point) at the end of a sentence.
       -- remove multiple spaces before a fullstop/point
    
       -- using gsub   
       local s = "Hello world.      I was here."
       x = s:gsub("%. +", ". ")                    -- replace multiple spaces with a single space
       --> hello world I was here
       local s = "Hello world. \t\r\n I was here."
       x = s:gsub("%.%s+", ". ")                   -- replace *any* multiple whitespace characters with a single space
       --> hello world I was here
       
       -- using rxsub   
       local s = "Hello world.      I was here.  "
       x = s:rxsub("\\. +", ". ")                  -- replace multiple spaces with a single space
       --> hello world I was here
       local s = "Hello world. \t\r\n I was here.  "
       x = s:rxsub("\\.\\s+", ". ")                -- replace *any* multiple whitespace characters with a single space
       --> hello world I was here
  4. This example demonstrates the use of a capture to duplicate words. To create a capture you enclose a phrase or pattern in brackets, then you can refer to it later as $1-9 (regex) or %1-9 (Lua pattern), you can also use $0 or %0 to refer to a complete string match. If there is no explicit capture then string.gsub() will capture a whole string match as %1 (which is equivalent to %0 in this case), we prefer %0 as it is more obvious as it is consistent with regex (see example below).
       -- using gsub   
       local s = "hello world"
       x = s:gsub("(%w+)", "%1 %1") -- %1 = first match
       x = s:gsub("(%w+)", "%0 %0") -- %0 = whole match
       x = s:gsub("(%w+)", "%1 %0") -- mixed = same result
       x = s:gsub("%w+", "%0 %0")   -- %0 = whole match
       x = s:gsub("%w+", "%1 %1")   -- %1 = first match (same result as %0) - equivalent regex (below) fails = not recommended
       --> x="hello hello world world"   
       
       -- using rxsub   
       local s = "hello world"
       x = s:rxsub("(\\w+)", "$1 $1") -- $1 = first match
       x = s:rxsub("(\\w+)", "$0 $0") -- $0 = whole match
       x = s:rxsub("\\w+", "$0 $0")   -- $0 = whole match
       x = s:rxsub("\\w+", "$1 $1")   -- $1 = first match fails - equivalent Lua pattern (above) works
       --> x="hello hello world world"
       
       -- notice how %0 or $0 is different from %1, %2 or $1, $2 when using multiple captures
       -- using gsub   
       local s = "hello world"
       x = s:gsub("(%w+) (%w+)", "%0 %0")   -- %0 = whole match   --> hello world hello world
       x = s:gsub("(%w+) (%w+)", "%1 %1")   -- %1 = first capture --> hello hello
       -- using rxsub   
       local s = "hello world"
       x = s:gsub("(\\w+) (\\w+)", "$0 $0")   -- %0 = whole match   --> hello world hello world
       x = s:gsub("(\\w+) (\\w+)", "$1 $1")   -- %1 = first capture --> hello hello
    
  5. A more useful example with captures is to use them to remove duplicate words. Notice how we can remove multiple repeated words with string.rxsub() but not with string.gsub(), this is because PCRE allows for repetition of captures to be quantified with (with * or +), but Lua Patterns do not allow this.
       -- remove duplicate words
    
       -- using gsub   
       local s = "hello hello world world I was here"
       x = s:gsub("(%w+)%s+%1","%1")                         -- can only remove duplicate words (not multiples like PCRE below)
       x = s:gsub("(%w+)(%s+%1)+","%1")                      -- cannot repeat a capture in Lua so THIS DOES NOT WORK         
       --> hello world I was here
    
       -- using rxsub   
       local s = "hello hello  hello world world I was here"
       x = s:rxsub("(\\b\\w+\\b)(\\W+\\1)+","$1")            -- using a word boundary \b
       --> hello world I was here                            -- our PCRE regex can remove multiple repeats (unlike gsub)
  6. Suppose we occasionally receive HL7 messages with an extra “|” character before the encoding characters (“MSH||^~\&“), we can remove this by using an “^” anchor to check and fix the start of the message.
    Note: You might think the anchor is overkill, but it will prevent matching things like embedded HL7 messages.

       -- Remove extra bar "|" character
    
       -- Note: The use of the [[<string>]] syntax to reduce escaping 
       -- i.e., for gsub() [[MSH|^~\&|]] rather than 'MSH|^~\\&|'
     
       -- using gsub   
       local s = [[MSH||^~\&|iNTERFACEWARE|Lab|]] -- partial HL7 message for brevity
       x = s:gsub([[^MSH||^~\&|]], [[MSH|^~\&|]])
       --> MSH|^~\&|iNTERFACEWARE|Lab|
       
       -- using rxsub   
       local s = [[MSH||^~\&|iNTERFACEWARE|Lab|]] -- partial HL7 message for brevity
       x = s:rxsub([[^MSH\|\|\^~\\&\|]], [[MSH|^~\\&|]])
       --> MSH|^~\&|iNTERFACEWARE|Lab|
  7. We can also use a “$” anchor to add a fullstop/point at the end of a string.
       -- put a fullstop/point at the end of the string
       
       -- using gsub   
       local s = "Hello world I was here"
       x = s:gsub('[^.]$', '%0.')
       --> Hello world I was here.
       
       -- using rxsub   
       local s = "Hello world I was here"
       x = s:rxsub('[^.]$', '$0.')
       --> Hello world I was here.
  8. This example demonstrates the use of multiple captures to reverse the order of consecutive words. Notice the use of the POSIX class [:alpha:] with string.rxsub() to match alphabetic characters.
       -- reverse the order of two consecutive words
       
       -- using gsub   
       local s = "one two three  four 5 6"
       x = s:gsub("(%w+)%s*(%w+)", "%2 %1")    -- %w for alphanumeric, %s* matches multiple spaces
       --> x="two one four three 6 5"          -- but multiple spaces are not included in the result
       local s = "one two three  four 5 6"
       x = s:gsub("(%w+)(%s*)(%w+)", "%3%2%1") -- 3 captures will include spaces in the result
       --> x="two one four  three 6 5"          
       local s = "one two three  four 5 6"
       x = s:gsub("(%a+)%s*(%a+)", "%2 %1")    -- %a for alphabetic only
       --> x="two one four three 5 6"
       
       -- using rxsub   
       local s = "one two three four 5 6"
       x = s:rxsub("(\\w+)\\s*(\\w+)", "$2 $1")                 -- \w for alphanumeric, \s* matches multiple spaces
       --> x="two one four three 6 5"
       local s = "one two three  four 5 6"
       x = s:rxsub("(\\w+)(\\s*)(\\w+)", "$3$2$1")              -- 3 captures will include spaces in the result
       --> x="two one four  three 6 5"          
       local s = "one two three four 5 6"
       x = s:rxsub("([[:alpha:]]+)\\s*([[:alpha:]]+)", "$2 $1") -- [:alpha:] (POSIX class) for alphabetic only
       --> x="two one four three 5 6"
    
  9. Convert URLs in text to hyperlinks:
    Note: This will not find “shorthand” URLs like “www.google.com” they needs to start with https:// (or http, ftp or ftps)

       -- convert URLs to hyperlinks
       
       local r = [[(http|https|ftp|ftps)\://[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(/[^\s,;:(?:. )]*)?]] -- URL regex
       
       -- text to match and update
       local s = 'We should match https://css-tricks.com/snippets/php/find-urls-in-text-make-links/, '.. 
                 'this https://gist.github.com/dperini/729294, this http://php.net/manual/en/book.pcre.php '..
                 'and this https://www.google.com, but not this www.google.com (without the https://)'
       
       if(s:rxmatch(r)) then      
          x = s:rxsub(r, "<a href=$0>$0</a>") -- create hyperlinks
       end
  10. Replace words in a foreign language like Greek or Cyrillic etc, by using unicode scripts.
    Note: You could use a call to translation web service rather than “<Greek word>”.

       -- Replace words in a foreign language
       
       local s = "Hello world in Greek Γειά σου Κόσμε (from google translate)"
       x = s:rxsub([[\p{Greek}+]], '<Greek word>', 'u') -- use a call to translation web service instead of "<Greek word>"
       trace(x)

PCRE Samples [top]

All of the examples follow a simple format: First the regex is listed, then one or two lines explaining what the regex does and how it works (usually including some sample).

The regex patterns are written using the Perl style delimiters /<regex expression>/<optional modifiers>, i.e., /hello/gi. To use the pattern in rxmatch() or rxsub() simply copy the regex to the regex (first) parameter and the modifiers (omitting the “g”modifier) to the mods parameter (2nd parameter for rxmatch() and the 4th for rxsub()).

The meanings of the modifiers used are:

  • “i” use case insensitive matching
  • “u” use Unicode character properties, required when using Unicode escape sequences “\X”, “\p{xx}” and “\P{xx}”
  • Note: Do not copy “g” it is included for use with regex testers, it means “global” and causes all matches to be returned (rather than just the first)

Tip: It is very easy to adapt PHP examples for Iguana, rxmatch() corresponds to preg_grep (and to a lesser extent preg_match), while rxsub() corresponds to preg_filter and preg_replace.

  1. The first example is very simple, it just matches any single word or phrase:
    /hello/gi
    Matches "Hello" and "hello" in the string "Hello hello world"
    
    /Hello world/gi
    Matches "hello world" in the string "Hello hello world"
    
    /\w+/g
    Matches each word in the string "hello world from Lua and PCRE"
    Also matches words digits and underscores, like this "matches 12_34 and my_name"
    

    Examples: See Using rxmatch() point 1 and Using rxsub() points 1.1 and 1.2.

  2. The second shows some Unicode word matching options with PCRE:
    /\X+/gu
    Matches words with special Unicode graphemes like "Áé©"
    
    /\p{Greek}+/gu
    Matches words using Greek Unicode graphemes
    
    /\p{L}+/gu
    Matches words using any Unicode Letter graphemes, excluding symbols like "©"

    Examples: See Using rxmatch() point 9 and Using rxsub() points 10.

  3. This third example is similar to the first two but matches spaces or whitespace (spaces, tab, newline, carriage return and vertical tab):
    / +/g
    Matches spaces
    
    /\s+/g
    Matches whitespace (spaces, tab, newline, carriage return and vertical tab)
    

    Examples: See Using rxsub() points 2 and 3.

  4. Match words or phrases, using captures:
    /(hello)/gi
    Matches "hello" and "hello" in the string "Hello hello world", by using a capture "(<captured text>)"
    
    /(Hello hello)/g
    Matches the phrase "Hello hello" in the string "Hello hello world" using a capture "
    
    /(\w+)/g
    Matches each word in a string using a capture
    
    /(\w+ \w+)/g
    Matches two consecutive words with a space between in a string using one capture
    
    /(\w+) (\w+)/g
    Matches two consecutive words with a space between in a string using two captures
    
    /(\w+)\W+(\w+)/g
    Matches two consecutive words with one or more non-word characters between from a string using two captures
  5. Examples: See Using rxsub() points 4.
  6. Match key value pairs, using captures:
    /(\w+)=(\w+)/g
    Matches each word in the string "hello world from Lua and PCRE"
    Also matches words digits and underscores, like this "matches 12_34 and my_name"

    Examples: See Using rxmatch() point 2 and Using rxsub() point 8.

  7. Find duplicated words, using captures:
    /(\b\w+\b)(\W+\1)/gi
    Matches "Hello hello" and "World world" in the string "Hello hello World world"
    
    /(\\b\\w+\\b)(?:\\W+\\1)+/gi
    Matches "Hello  hello   hello" and "World world" in the string "Hello  hello   hello World world"
    Note: This regex is designed to match multiple words repeats with multiple non-word characters between the words.

    Examples: See Using rxmatch() point 3 and Using rxsub() points 5.

  8. Find a word (or pattern) in a string that is not followed by another word, using a negative lookahead (a PCRE “lookaround” subpattern”):
    /(hello)(?!.*world)/gi
    Matches "Hello" and "hello" in the string "Hello hello everyone my name is ..."
    Does not match "Hello" or "hello" in the string "Hello hello world"

    Examples: See Using rxmatch() point 4.

  9. Anchoring enables you to anchor a match to the start (^) or end ($) of the string being searched:
    /^hello/
    Matches "hello" at the start of "hello world"
    Does not match "hello" in "I said hello" or "she said hello to me"
    
    /hello$/
    Matches "hello" at the end of "I said hello"
    Does not match "hello" in "hello world" or "she said hello to me"

    Examples: See Using rxsub() points 6 and 7.

  10. You can use the free space mode “(?x)” inline modifier to include comments in a regex, though we usually prefer Lua comments in the Translator.

    /(?x)hello # this is a comment/
    
    /(?x)# Match a 20th or 21st century date in yyyy-mm-dd format
    (19|20)\d\d              # year (group 1)
    [- \/.]                  # separator
    (0[1-9]|1[012])          # month (group 2)
    [- \/.]                  # separator
    (0[1-9]|[12][0-9]|3[01]) # day (group 3)/

    Note: Commenting can be useful for complex regex expressions, like this one to match numbers in Plain English.

  11. Find text in delimiters, like brackets, quotes etc.
    1. Find quoted text:
      /((["'])[^\2]+\2)/
      Matches [["Don't wait up"]] including quotes at the end of [[She said "Don't wait up"]]
      
      /(["'])([^\1]+)\1/
      Matches [[Don't wait up]] excluding quotes at the end of [[She said "Don't wait up"]]

      Examples: See Using rxmatch() point 5.

    2. Find text inside brackets or other delimiters:
      Note: The example shown captures text in brackets “()” but you can substitute other delimiters.

      /(\([^)]+\))/
      Matches (and everyone)" including brackets at the end of "Hello to the world (and everyone)"
      
      /\(([^)]+)\)/
      Matches "and everyone" excluding brackets at the end of "Hello to the world (and everyone)"

      Examples: See Using rxmatch() point 6.

    3. Extract HTML or XML tags:
      /(<[^>]+>)/
      Matches (extracts) the HTML tags from "<a href="#hello_world">Hello world link</a>"
      Matches (extracts) the XML tags from
      [[<?xml version="1.0"?>
       <patients>
       <patient id = "123">
       <first-name>John</first-name>
       <last-name>Smith</last-name>
       </patient>
       </patients>]]
      
      /(<[^>]+\sid\\b[^>]+>)/
      Matches (extracts) only the XML tags that contain an "id" attribute from
      [[<?xml version="1.0"?>
       <patients>
       <patient id = "123">
       <first-name>John</first-name>
       <last-name>Smith</last-name>
       </patient>
       </patients>]]

      Examples: See Using rxmatch() point 7.

  12. White-listing and black-listing are useful both useful techniques.
    1. White-listing:
      /\b(hello|world)\b/gi
      Matches "Hello", "hello", "World" and "world" in the string "Hello hello World I was here world"
      

      Examples: See Using rxmatch() point 8.1.

    2. Black-listing:
      /\bhello\b(*SKIP)(*FAIL)|\bworld\b(*SKIP)(*FAIL)|\w+/gi
      Does not match "Hello", "hello", "World" and "world" in the string "Hello hello World I was here world"
      
      /\b(?:hello|world)\b(*SKIP)(*F)|\w+/gi
      More compact version using a non-capturing group so you only have to write (*SKIP)(*F) once, good for long lists
      Note: (*F) is shorthand for (*FAIL)

      Examples: See Using rxmatch() point 8.2.

  13. Here are some examples of Unicode matching.
    1. First up examples to help understand matching a specific unicode grapheme (compound character) like “à”:
      Note: The unicode “à” is composed of two code points (symbols): U+0061 (a) followed by U+0300 (grave accent).

      /^..$/
      Matches "à" (because it is two Unicode code points)
      
      /^.$/
      No match for "à" (because it is two Unicode code points)
      
      /\X$/u
      Matches "à" as "\X" matches all Unicode graphemes (the Unicode equivalent of ".")
      Note: The "\X" includes newline characters also, while "." does not (though using "." in DOTALL mode will match newlines)

      Examples: See Using rxmatch() point 9.1.

    2. Some other basic Unicode matching examples:
      /\X/gu
      Matches every character/grapheme in the string "Ábcd éfgh ©copyright" ("\X" matches Unicode  graphemes)
      
      /\p{L}/gu
      Matches every grapheme except the two spaces and the "©" in the string "Ábcd éfgh ©copyright" ("\p{L}" matches Unicode letter graphemes)
      
      /\p{Ll}/gu
      Matches every grapheme except "Á", the two spaces and the "©" in the string "Ábcd éfgh ©copyright" ("\p{Lu}" matches Unicode lower case letter graphemes)
      
      /\p{Lu}/gu
      Matches only the "Á" in the string "Ábcd éfgh ©copyright" ("\p{Lu}" matches Unicode upper case letter graphemes)
      
      /\p{S}/gu
      Matches only the "©" in the string "Ábcd éfgh ©copyright" ("\p{S}" matches Unicode symbol graphemes)
      
      

      Examples: See Using rxmatch() point 9.2 and Using rxsub() point 10.

    3. Match graphemes for a specified language, using unicode scripts like \p{Greek} or \p{Cyrillic}, etc:
      /\p{Greek}/gu
      Matches "Γειά σου Κόσμε" in the string "Hello world in Greek Γειά σου Κόσμε (from google translate)"
      
      /\P{Greek}/gu
      Matches all non Greek graphemes in the string "Hello world in Greek Γειά σου Κόσμε (from google translate)"

      Examples: See Using rxmatch() point 9.3.

  14. Match URLs found in plain text:
    Note: URL matching is not really this easy, see In search of the perfect URL validation regex and this regex gist for more complete answers.

    /(http|https|ftp|ftps)://[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(/[^\s,;:(?:. )]*)?/
    Sample string (Lua format):
    'We should match https://css-tricks.com/snippets/php/find-urls-in-text-make-links/, '.. 
    'this https://gist.github.com/dperini/729294, this http://php.net/manual/en/book.pcre.php '..
    'and this https://www.google.com, but not this www.google.com (without the https://)'
    Matches any valid URL that starts with http:// (or https, ftp, ftps) 
    Does not match "shorthand" URLs like this www.google.com (without the https://)
    

    Examples: See Using rxsub() point 9.

  15. To match balanced nested delimiters like brackets etc. you can use recursion “(?R)” or a subroutine call “(?1)”:
    Note: You can change these to use any delimiter.

    /(\((?>[^()]|(?R))*\))/g
    Use recursion to match the balanced nested brackets from "Recursively match balanced brackets (match) (((another match))) ((((and) matches) up) to here) but not here)) or here) etc))))"
    
    /\A(\((?:[^()]|(?1))*\))\z/g
    Use a subroutine call to match balanced string that starts and ends with brackets, like: "(((Will match a balanced()) string with the brackets (delimiters) at the start) and at the end)"
  16. Validate usernames and passwords.
    1. Validate a username, by allowing 3 to 15 characters in lower case including digits or “_-” symbols (similar rules as many websites):
      /^[a-z0-9_-]{3,15}$/
      Matches 3 to 15 lower case characters including digits and "_-" symbols
      
      /^[a-zA-Z0-9_-]{3,15}$/
      Allow uppercase characters as well
      
      /^[a-zA-Z][a-z0-9_-]{3,14}$/
      Allow an uppercase characters in the first position only
    2. Validate a password, by enforcing 6 to 18 characters including (one or more of) lower case, upper case, digits and “_-” symbols (similar rules as many websites):
      /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?!.*\s).{6,18}$/
      Enforces (matches) 6 to 18 characters including (one or more of) lower case, upper case, digits and “_-” symbols
      
      /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*\W)(?!.*\s).{6,18}$/
      Require special (non word "
  17. And there are still many more PCRE features and techniques that you may wish to investigate, like: backreferences, conditionals (if then else), subroutines, backtracking, zero-length matches, etc.
  18. And as a parting gift the simple task of creating a regex for matching/validating email addresses:
    Note: As you probably guessed it is not so simple, see this discussion or see this expression for RFC822.

    /^(?:[a-zA-Z0-9_\-\.]+)@(?:(?:\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(?:(?:[a-zA-Z0-9\-]+\.)+))(?:[a-zA-Z]{2,4}|[0-9]{1,3})(?:\]?)$/
    Allows for most things, including ip address, country code domains and "-_" characters in the name etc.
    
    And for your edification here is the nearest thing I can find to an "Official" regex for email (though it does come with some caveats and a warning that it may be out of date...):
    /(?:(?:\r\n)?[ \t])*(?:(?:(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t]
    )+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:
    \r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(
    ?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ 
    \t]))*"(?:(?:\r\n)?[ \t])*))*@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\0
    31]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\
    ](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+
    (?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:
    (?:\r\n)?[ \t])*))*|(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z
    |(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)
    ?[ \t])*)*\<(?:(?:\r\n)?[ \t])*(?:@(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\
    r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[
     \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)
    ?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t]
    )*))*(?:,@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[
     \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*
    )(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t]
    )+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*)
    *:(?:(?:\r\n)?[ \t])*)?(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+
    |\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r
    \n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:
    \r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t
    ]))*"(?:(?:\r\n)?[ \t])*))*@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031
    ]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](
    ?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?
    :(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?
    :\r\n)?[ \t])*))*\>(?:(?:\r\n)?[ \t])*)|(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?
    :(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?
    [ \t]))*"(?:(?:\r\n)?[ \t])*)*:(?:(?:\r\n)?[ \t])*(?:(?:(?:[^()<>@,;:\\".\[\] 
    \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|
    \\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>
    @,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"
    (?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*))*@(?:(?:\r\n)?[ \t]
    )*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\
    ".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?
    :[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[
    \]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*|(?:[^()<>@,;:\\".\[\] \000-
    \031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(
    ?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)*\<(?:(?:\r\n)?[ \t])*(?:@(?:[^()<>@,;
    :\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([
    ^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\"
    .\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\
    ]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*(?:,@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\
    [\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\
    r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] 
    \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]
    |\\.)*\](?:(?:\r\n)?[ \t])*))*)*:(?:(?:\r\n)?[ \t])*)?(?:[^()<>@,;:\\".\[\] \0
    00-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\
    .|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,
    ;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?
    :[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*))*@(?:(?:\r\n)?[ \t])*
    (?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".
    \[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[
    ^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]
    ]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*\>(?:(?:\r\n)?[ \t])*)(?:,\s*(
    ?:(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\
    ".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)(?:\.(?:(
    ?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[
    \["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t
    ])*))*@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t
    ])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?
    :\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|
    \Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*|(?:
    [^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\
    ]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)*\<(?:(?:\r\n)
    ?[ \t])*(?:@(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["
    ()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)
    ?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>
    @,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*(?:,@(?:(?:\r\n)?[
     \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,
    ;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t]
    )*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\
    ".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*)*:(?:(?:\r\n)?[ \t])*)?
    (?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".
    \[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)(?:\.(?:(?:
    \r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\[
    "()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])
    *))*@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])
    +|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\
    .(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z
    |(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*\>(?:(
    ?:\r\n)?[ \t])*))*)?;\s*)/
    

More Information [top]

Leave A Comment?