PCRE Samples
Contents
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.
- 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.
- 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.
- 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.
- 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
- Examples: See Using rxsub() points 4.
- 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.
- 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.
- 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.
- 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.
- 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.
- Find text in delimiters, like brackets, quotes etc.
- 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.
- 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.
- 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.
- Find quoted text:
- White-listing and black-listing are useful both useful techniques.
- 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.
- 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.
- White-listing:
- Here are some examples of Unicode matching.
- 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.
- 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.
- 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.
- First up examples to help understand matching a specific unicode grapheme (compound character) like “à”:
- 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.
- 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)"
- Validate usernames and passwords.
- 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
- 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 "
- Validate a username, by allowing 3 to 15 characters in lower case including digits or “_-” symbols (similar rules as many websites):
- 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.
- 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*)/