diff --git a/README.md b/README.md
index 57a294e..2b6e8f8 100644
--- a/README.md
+++ b/README.md
@@ -7,7 +7,13 @@
![rex-gopher](_docs/gopher.png)
-This is a regular expressions builder for gophers!
+**This is a regular expressions builder for gophers!**
+
+- **[Why?](#why)**
+- **[FAQ](#faq)**
+- **[Documentation](_docs/library.md)**
+- **[Examples](pkg/examples_test.go)**
+- **[License](#license)**
## Why?
@@ -15,9 +21,9 @@ It makes readability better and helps to construct regular expressions using hum
It is just a builder, so it returns standart [`*regexp.Regexp`](https://pkg.go.dev/regexp#Regexp).
-The library supports [groups](#groups), [composits](#simple-composite), [classes](#character-classes), [flags](#flags), [repetitions](#repetitions) and if you want you can even use [raw regular expressions](#raw-regular-expression) in any place. Also it contains a set of [predefined helpers](#helper) for matching phones, emails, etc...
+The library supports [groups](_docs/library.md#groups), [composits](_docs/library.md#groups), [classes](_docs/library.md#character-classes), [flags](_docs/library.md#flags), [repetitions](_docs/library.md#repetitions) and if you want you can even use `raw regular expressions` in any place. Also it contains a set of [predefined helpers](_docs/library.md#helper) with patterns for number ranges, phones, emails, etc...
-Let's see an example of validating or matching `some_id[#]` using verbose patterns:
+Let's see an example of validating or matching `someid[#]` using a verbose pattern:
```golang
re := rex.New(
rex.Chars.Begin(), // `^`
@@ -36,231 +42,95 @@ re := rex.New(
Yes, it requires more code, but it has its advantages.
> More, but simpler code, fewer bugs.
-You can still use original regular expressions. Example of matching
-numbers between `-111.99` and `1111.99` using a combination of patterns
-and raw regular expression:
+You can still use original regular expressions as is in any place. Example of
+matching numbers between `-111.99` and `1111.99` using a combination of
+patterns and raw regular expression:
```golang
re := rex.New(
rex.Common.Raw(`^`),
rex.Helper.NumberRange(-111, 1111),
- rex.Common.Raw(`\.[0-9]{2}$`),
+ rex.Common.RawVerbose(`
+ # RawVerbose is a synonym to Raw,
+ # but ignores comments, spaces and new lines.
+ \. # Decimal delimter.
+ [0-9]{2} # Only two digits.
+ $ # The end.
+ `),
).MustCompile()
// Produces:
// ^((?:\x2D(?:0|(?:[1-9])|(?:[1-9][0-9])|(?:10[0-9])|(?:11[0-1])))|(?:0|(?:[1-9])|(?:[1-9][0-9])|(?:[1-9][0-9][0-9])|(?:10[0-9][0-9])|(?:110[0-9])|(?:111[0-1])))\.[0-9]{2}$
```
+> The style you prefer is up to you.
+
## Meme
-_The picture contains two frame fragments from [the video](https://www.youtube.com/watch?v=uxpDa-c-4Mc)._
-
-## Documentation
-
-```golang
-import "github.com/hedhyw/rex/pkg/rex"
-
-func main() {
- rex.New(/* tokens */).MustCompile() // The same as `regexp.MustCompile`.
- rex.New(/* tokens */).Compile() // The same as `regexp.Compile`.
- rex.New(/* tokens */).String() // Get constructed regular expression as a string.
-}
-```
-
-### Common
-
-Common operators for core operations.
-
-```golang
-rex.Common.Raw(raw string) // Raw regular expression.
-rex.Common.Text(text string) // Escaped text.
-rex.Common.Class(tokens ...dialect.ClassToken) // Include specified characters.
-rex.Common.NotClass(tokens ...dialect.ClassToken) // Exclude specified characters.
-```
-
-### Character classes
-
-Single characters and classes, that can be used as-is, as well as childs to `rex.CommonClass` or `rex.CommonNotClass`.
-
-```golang
-rex.Chars.Begin() // `^`
-rex.Chars.End() // `$`
-rex.Chars.Any() // `.`
-rex.Chars.Range('a', 'z') // `[a-z]`
-rex.Chars.Runes("abc") // `[abc]`
-rex.Chars.Single('r') // `r`
-rex.Chars.Unicode(unicode.Greek) // `\p{Greek}`
-rex.Chars.UnicodeByName("Greek") // `\p{Greek}`
-
-rex.Chars.Digits() // `[0-9]`
-rex.Chars.Alphanumeric() // `[0-9A-Za-z]`
-rex.Chars.Alphabetic() // `[A-Za-z]`
-rex.Chars.ASCII() // `[\x00-\x7F]`
-rex.Chars.Whitespace() // `[\t\n\v\f\r ]`
-rex.Chars.WordCharacter() // `[0-9A-Za-z_]`
-rex.Chars.Blank() // `[\t ]`
-rex.Chars.Control() // `[\x00-\x1F\x7F]`
-rex.Chars.Graphical() // `[[:graph:]]`
-rex.Chars.Lower() // `[a-z]`
-rex.Chars.Printable() // `[ [:graph:]]`
-rex.Chars.Punctuation() // `[!-/:-@[-`{-~]`
-rex.Chars.Upper() // `[A-Z]`
-rex.Chars.HexDigits() // `[0-9A-Fa-f]`
-```
-
-If you want to combine mutiple character classes, use `rex.Common.Class`:
-```golang
-// Only specific characters:
-rex.Common.Class(rex.Chars.Digits(), rex.Chars.Single('a'))
-// It will produce `[0-9a]`.
-
-// All characters except:
-rex.Common.NotClass(rex.Chars.Digits(), rex.Chars.Single('a'))
-// It will produce `[^0-9a]`.
-```
-
-### Groups
-
-Helpers for grouping expressions.
-
-```golang
-// Define a captured group. That can help to select part of the text.
-rex.Group.Define(rex.Chars.Single('a'), rex.Chars.Single('b')) // (ab)
-// A group that defines "OR" condition for given expressions.
-// Example: "a" or "rex", ...
-rex.Group.Composite(rex.Chars.Single('a'), rex.Common.Text("rex")) // (?:a|rex)
-// Define non-captured group. The result will not be captured.
-rex.Group.NonCaptured(rex.Chars.Single('a')) // (?:a)
-
-// Define a group with a name.
-rex.Group.Define(rex.Chars.Single('a')).WithName("my_name") // (?Pa)
-```
-
-## Flags
-
-```golang
-// TODO: https://github.com/hedhyw/rex/issues/31
-```
-
-### Repetitions
+## FAQ
-Helpers that specify how to repeat characters. They can be called on character class tokens.
+1. **It is too verbose. Too much code.**
-```golang
-RepetableClassToken.Repeat().OneOrMore() // `+`
-RepetableClassToken.ZeroOrMore() // `*`
-RepetableClassToken.ZeroOrOne() // `?`
-RepetableClassToken.EqualOrMoreThan(n int) // `{n,}`
-RepetableClassToken.Between(n, m int) // `{n,m}`
-
-// Example:
-rex.Chars.Digits().Repeat().OneOrMore() // [0-9]+
-rex.Group.Define(rex.Chars.Single('a')).Repeat().OneOrMore() // (a)+
-```
+ More, but simpler code, fewer bugs.
+ Anyway, you can still use the raw regular expressions syntax in combination with helpers.
+ ```golang
+ rex.New(
+ rex.Chars.Begin(),
+ rex.Group.Define(
+ // `Raw` can be placed anywhere in blocks.
+ rex.Common.Raw(`[a-z]+\d+[A-Z]*`),
+ ),
+ rex.Chars.End(),
+ )
+ ```
+ Or just raw regular expression with comments:
+ ```golang
+ rex.Common.RawVerbose(`
+ ^ # Start of the line.
+ [a-zA-Z0-9]+ # Local part.
+ @ # delimeter.
+ [a-zA-Z0-9\.]+ # Domain part.
+ $ # End of the line.
+ `)
+ ```
-## Helper
+2. **Should I know regular expressions?**
-Common regular expression patters that are ready to use.
-> ⚠️ These patterns are likely to be changed in new versions.
+ It is better to know them in order to use this library most effectively.
+ But in any case, it is not strictly necessary.
-```golang
-rex.Helper.NumberRange(-5, 123) // Defines number range pattern without leading zeros.
-rex.Helper.Phone() // Combines PhoneE164 and PhoneE123.
-rex.Helper.PhoneE164() // +155555555
-rex.Helper.PhoneE123() // Combines PhoneNationalE123 and PhoneInternationalE123.
-rex.Helper.PhoneNationalE123() // (607) 123 4567
-rex.Helper.PhoneInternationalE123() // +22 607 123 4567
-rex.Helper.HostnameRFC952() // Hostname by RFC-952 (stricter).
-rex.Helper.HostnameRFC1123() // Hostname by RFC-1123.
-rex.Helper.Email() // Unquoted email pattern, it doesn't check RFC 5322 completely, due to high complexity.
-rex.Helper.IP() // IPv4 or IPv6.
-rex.Helper.IPv4() // 127.0.0.1 (without leading zeros)
-rex.Helper.IPv6() // 2001:0db8:85a3:0000:0000:8a2e:0370:7334
-rex.Helper.MD5Hex() // d41d8cd98f00b204e9800998ecf8427e
-rex.Helper.SHA1Hex() // da39a3ee5e6b4b0d3255bfef95601890afd80709
-rex.Helper.SHA256Hex() // e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
-```
+3. **Is it language-dependent? Is it transferable to other languages?**
-## Examples
+ We can use this library only in Go. If you want to use any parts
+ in other places, then just call `rex.New(...).String()` and copy-paste
+ generated regular expression.
-### Simple email validator
+4. **What about my favourite `DSL`?**
-Let's describe a simple email regular expression in order to show the basic functionality (there is a more advanced helper `rex.Helper.Email()`):
+ Every IDE has convenient auto-completion for languages. So all helpers
+ of this library are easy to use out of the box. Also, it is easier
+ to create custom parameterized helpers.
-```golang
-// We can define a set of characters and reuse the block.
-customCharacters := rex.Common.Class(
- rex.Chars.Range('a', 'z'), // `[a-z]`
- rex.Chars.Upper(), // `[A-Z]`
- rex.Chars.Single('-'), // `\x2D`
- rex.Chars.Digits(), // `[0-9]`
-) // `[a-zA-Z-0-9]`
+5. **Is it stable?**
-re := rex.New(
- rex.Chars.Begin(), // `^`
- customCharacters.Repeat().OneOrMore(),
-
- // Email delimeter.
- rex.Chars.Single('@'), // `@`
-
- // Allow dot after delimter.
- rex.Common.Class(
- rex.Chars.Single('.'), // \.
- customCharacters,
- ).Repeat().OneOrMore(),
-
- // Email should contain at least one dot.
- rex.Chars.Single('.'), // `\.`
- rex.Chars.Alphanumeric().Repeat().Between(2, 3),
+ It is `0.X.Y` version, but there are some backward compatibility guarantees:
+ - `rex.Chars` helpers can change output to an alternative synonym.
+ - `rex.Common` helpers can be deprecated, but not removed.
+ - `rex.Group` some methods can be deprecated.
+ - `rex.Helper` can be changed with breaking changes due to specification complexities.
+ - The test coverage should be `~100%` without covering [test helpers](internal/test/test.go).
+ - Any breaking change will be prevented as much as possible.
- rex.Chars.End(), // `$`
-).MustCompile()
-```
+ _All of the above may not be respected when upgrading the major version._
-#### Simple composite
+6. **I have another question. I found an issue. I have a feature request. I want to contribute.**
-```golang
-re := rex.New(
- rex.Chars.Begin(),
- rex.Group.Composite(
- // Text matches exact text (symbols will be escaped).
- rex.Common.Text("hello."),
- // OR one or more numbers.
- rex.Chars.Digits().Repeat().OneOrMore(),
- ),
- rex.Chars.End(),
-).MustCompile()
-
-re.MatchString("hello.") // true
-re.MatchString("hello") // false
-re.MatchString("123") // true
-re.MatchString("hello.123") // false
-```
-
-## Example match usage
-
-```golang
-re := rex.New(
- // Define a named group.
- rex.Group.Define(
- rex.Helper.Phone(),
- ).WithName("phone"),
-).MustCompile()
-
-const text = `
-E.164: +15555555
-E.123.Intl: (607) 123 4567
-E.123.Natl: +22 607 123 4567
-`
-
-submatches := re.FindAllStringSubmatch(text, -1)
-// submatches[0]: +15555555
-// submatches[1]: (607) 123 4567
-// submatches[2]: +22 607 123 4567
-```
+ Please, [create an issue](https://github.com/hedhyw/rex/issues/new?labels=question&title=I+have+a+question).
-#### More examples
+## License
-More examples can be found here: [examples_test.go](examples_test.go).
+- The library is under [MIT Lecense](LICENSE)
+- [The gopher](_docs/gopher.png) is under [Creative Commons Attribution 3.0](https://creativecommons.org/licenses/by/3.0/) license. It was originally created by [Renée French](https://en.wikipedia.org/wiki/Ren%C3%A9e_French) and redrawed by me.
+- [The meme](_docs/meme.png) contains two frame fragments from [the video](https://www.youtube.com/watch?v=uxpDa-c-4Mc).
diff --git a/_docs/examples.md b/_docs/examples.md
new file mode 100644
index 0000000..d39e8ab
--- /dev/null
+++ b/_docs/examples.md
@@ -0,0 +1,82 @@
+
+## Examples
+
+### Simple email validator
+
+Let's describe a simple email regular expression in order to show the basic functionality (there is a more advanced helper `rex.Helper.Email()`):
+
+```golang
+// We can define a set of characters and reuse the block.
+customCharacters := rex.Common.Class(
+ rex.Chars.Range('a', 'z'), // `[a-z]`
+ rex.Chars.Upper(), // `[A-Z]`
+ rex.Chars.Single('-'), // `\x2D`
+ rex.Chars.Digits(), // `[0-9]`
+) // `[a-zA-Z-0-9]`
+
+re := rex.New(
+ rex.Chars.Begin(), // `^`
+ customCharacters.Repeat().OneOrMore(),
+
+ // Email delimeter.
+ rex.Chars.Single('@'), // `@`
+
+ // Allow dot after delimter.
+ rex.Common.Class(
+ rex.Chars.Single('.'), // \.
+ customCharacters,
+ ).Repeat().OneOrMore(),
+
+ // Email should contain at least one dot.
+ rex.Chars.Single('.'), // `\.`
+ rex.Chars.Alphanumeric().Repeat().Between(2, 3),
+
+ rex.Chars.End(), // `$`
+).MustCompile()
+```
+
+#### Simple composite
+
+```golang
+re := rex.New(
+ rex.Chars.Begin(),
+ rex.Group.Composite(
+ // Text matches exact text (symbols will be escaped).
+ rex.Common.Text("hello."),
+ // OR one or more numbers.
+ rex.Chars.Digits().Repeat().OneOrMore(),
+ ),
+ rex.Chars.End(),
+).MustCompile()
+
+re.MatchString("hello.") // true
+re.MatchString("hello") // false
+re.MatchString("123") // true
+re.MatchString("hello.123") // false
+```
+
+## Example match usage
+
+```golang
+re := rex.New(
+ // Define a named group.
+ rex.Group.Define(
+ rex.Helper.Phone(),
+ ).WithName("phone"),
+).MustCompile()
+
+const text = `
+E.164: +15555555
+E.123.Intl: (607) 123 4567
+E.123.Natl: +22 607 123 4567
+`
+
+submatches := re.FindAllStringSubmatch(text, -1)
+// submatches[0]: +15555555
+// submatches[1]: (607) 123 4567
+// submatches[2]: +22 607 123 4567
+```
+
+#### More examples
+
+More examples can be found here: [examples_test.go](examples_test.go).
diff --git a/_docs/library.md b/_docs/library.md
new file mode 100644
index 0000000..abe07cb
--- /dev/null
+++ b/_docs/library.md
@@ -0,0 +1,127 @@
+## Documentation
+
+[![PkgGoDev](https://pkg.go.dev/badge/github.com/hedhyw/rex)](https://pkg.go.dev/github.com/hedhyw/rex?tab=doc)
+
+```golang
+import "github.com/hedhyw/rex/pkg/rex"
+
+func main() {
+ rex.New(/* tokens */).MustCompile() // The same as `regexp.MustCompile`.
+ rex.New(/* tokens */).Compile() // The same as `regexp.Compile`.
+ rex.New(/* tokens */).String() // Get constructed regular expression as a string.
+}
+```
+
+### Common
+
+Common operators for core operations.
+
+```golang
+rex.Common.Raw(raw string) // Raw regular expression.
+rex.Common.Text(text string) // Escaped text.
+rex.Common.Class(tokens ...dialect.ClassToken) // Include specified characters.
+rex.Common.NotClass(tokens ...dialect.ClassToken) // Exclude specified characters.
+```
+
+### Character classes
+
+Single characters and classes, that can be used as-is, as well as childs to `rex.CommonClass` or `rex.CommonNotClass`.
+
+```golang
+rex.Chars.Begin() // `^`
+rex.Chars.End() // `$`
+rex.Chars.Any() // `.`
+rex.Chars.Range('a', 'z') // `[a-z]`
+rex.Chars.Runes("abc") // `[abc]`
+rex.Chars.Single('r') // `r`
+rex.Chars.Unicode(unicode.Greek) // `\p{Greek}`
+rex.Chars.UnicodeByName("Greek") // `\p{Greek}`
+
+rex.Chars.Digits() // `[0-9]`
+rex.Chars.Alphanumeric() // `[0-9A-Za-z]`
+rex.Chars.Alphabetic() // `[A-Za-z]`
+rex.Chars.ASCII() // `[\x00-\x7F]`
+rex.Chars.Whitespace() // `[\t\n\v\f\r ]`
+rex.Chars.WordCharacter() // `[0-9A-Za-z_]`
+rex.Chars.Blank() // `[\t ]`
+rex.Chars.Control() // `[\x00-\x1F\x7F]`
+rex.Chars.Graphical() // `[[:graph:]]`
+rex.Chars.Lower() // `[a-z]`
+rex.Chars.Printable() // `[ [:graph:]]`
+rex.Chars.Punctuation() // `[!-/:-@[-`{-~]`
+rex.Chars.Upper() // `[A-Z]`
+rex.Chars.HexDigits() // `[0-9A-Fa-f]`
+```
+
+If you want to combine mutiple character classes, use `rex.Common.Class`:
+```golang
+// Only specific characters:
+rex.Common.Class(rex.Chars.Digits(), rex.Chars.Single('a'))
+// It will produce `[0-9a]`.
+
+// All characters except:
+rex.Common.NotClass(rex.Chars.Digits(), rex.Chars.Single('a'))
+// It will produce `[^0-9a]`.
+```
+
+### Groups
+
+Helpers for grouping expressions.
+
+```golang
+// Define a captured group. That can help to select part of the text.
+rex.Group.Define(rex.Chars.Single('a'), rex.Chars.Single('b')) // (ab)
+// A group that defines "OR" condition for given expressions.
+// Example: "a" or "rex", ...
+rex.Group.Composite(rex.Chars.Single('a'), rex.Common.Text("rex")) // (?:a|rex)
+// Define non-captured group. The result will not be captured.
+rex.Group.NonCaptured(rex.Chars.Single('a')) // (?:a)
+
+// Define a group with a name.
+rex.Group.Define(rex.Chars.Single('a')).WithName("my_name") // (?Pa)
+```
+
+## Flags
+
+```golang
+// TODO: https://github.com/hedhyw/rex/issues/31
+```
+
+### Repetitions
+
+Helpers that specify how to repeat characters. They can be called on character class tokens.
+
+```golang
+RepetableClassToken.Repeat().OneOrMore() // `+`
+RepetableClassToken.ZeroOrMore() // `*`
+RepetableClassToken.ZeroOrOne() // `?`
+RepetableClassToken.EqualOrMoreThan(n int) // `{n,}`
+RepetableClassToken.Between(n, m int) // `{n,m}`
+
+// Example:
+rex.Chars.Digits().Repeat().OneOrMore() // [0-9]+
+rex.Group.Define(rex.Chars.Single('a')).Repeat().OneOrMore() // (a)+
+```
+
+## Helper
+
+Common regular expression patters that are ready to use.
+> ⚠️ These patterns are likely to be changed in new versions.
+
+```golang
+rex.Helper.NumberRange(-5, 123) // Defines number range pattern without leading zeros.
+rex.Helper.Phone() // Combines PhoneE164 and PhoneE123.
+rex.Helper.PhoneE164() // +155555555
+rex.Helper.PhoneE123() // Combines PhoneNationalE123 and PhoneInternationalE123.
+rex.Helper.PhoneNationalE123() // (607) 123 4567
+rex.Helper.PhoneInternationalE123() // +22 607 123 4567
+rex.Helper.HostnameRFC952() // Hostname by RFC-952 (stricter).
+rex.Helper.HostnameRFC1123() // Hostname by RFC-1123.
+rex.Helper.Email() // Unquoted email pattern, it doesn't check RFC 5322 completely, due to high complexity.
+rex.Helper.IP() // IPv4 or IPv6.
+rex.Helper.IPv4() // 127.0.0.1 (without leading zeros)
+rex.Helper.IPv6() // 2001:0db8:85a3:0000:0000:8a2e:0370:7334
+rex.Helper.MD5Hex() // d41d8cd98f00b204e9800998ecf8427e
+rex.Helper.SHA1Hex() // da39a3ee5e6b4b0d3255bfef95601890afd80709
+rex.Helper.SHA256Hex() // e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
+```
diff --git a/pkg/dialect/base/common.go b/pkg/dialect/base/common.go
index 0940de1..9e2782b 100644
--- a/pkg/dialect/base/common.go
+++ b/pkg/dialect/base/common.go
@@ -17,7 +17,20 @@ const Common CommonBaseDialect = "CommonBaseDialect"
// Raw appends regular expression as is.
func (CommonBaseDialect) Raw(raw string) RawToken {
- return RawToken{value: raw}
+ return RawToken{value: raw, verbose: true}
+}
+
+// RawVerbose appends regular expression and removes comments, spaces and new lines.
+//
+// When a line contains a # that is not in a character class and is not
+// preceded by an unescaped backslash, all characters from the leftmost
+// such # through the end of the line are ignored.
+//
+// Leading and trailling whitespaces are ignored.
+//
+// It also ignores all new lines.
+func (CommonBaseDialect) RawVerbose(raw string) RawToken {
+ return RawToken{value: raw, verbose: true}
}
// Text appends the text, and escapes all regular expression metacharacters.
diff --git a/pkg/dialect/base/raw.go b/pkg/dialect/base/raw.go
index ae56421..dcd5ae8 100644
--- a/pkg/dialect/base/raw.go
+++ b/pkg/dialect/base/raw.go
@@ -1,10 +1,15 @@
package base
-import "github.com/hedhyw/rex/pkg/dialect"
+import (
+ "strings"
+
+ "github.com/hedhyw/rex/pkg/dialect"
+)
// RawToken holds raw regular expression.
type RawToken struct {
- value string
+ value string
+ verbose bool
}
// Unwrap implements dialect.ClassToken.
@@ -14,5 +19,58 @@ func (rt RawToken) Unwrap() dialect.ClassToken {
// WriteTo implements dialect.Token interface.
func (rt RawToken) WriteTo(w dialect.StringByteWriter) (n int, err error) {
- return w.WriteString(rt.value)
+ value := rt.value
+
+ if rt.verbose {
+ lines := strings.Split(value, "\n")
+ for i, l := range lines {
+ l = removeComment(l)
+ l = strings.ReplaceAll(l, "\\#", "#")
+ l = strings.TrimSpace(l)
+ lines[i] = l
+ }
+
+ value = strings.Join(lines, "")
+ }
+
+ return w.WriteString(value)
+}
+
+// removeComment removes everythong after '#' if it is not escaped by
+// backslash '\#' or it is not in the character class '[#]'.
+//
+// This input:
+// .+\#[#] # comment
+// Will be converted to:
+// .+\#[#]
+func removeComment(val string) string {
+ var (
+ backslash bool
+ characterClass bool
+ )
+
+ for i, ch := range val {
+ switch ch {
+ case '\\':
+ backslash = !backslash
+
+ continue
+ case '#':
+ if !backslash && !characterClass {
+ return string([]rune(val)[:i])
+ }
+ case '[':
+ if !backslash {
+ characterClass = true
+ }
+ case ']':
+ if !backslash {
+ characterClass = false
+ }
+ }
+
+ backslash = false
+ }
+
+ return val
}
diff --git a/pkg/dialect/base/raw_test.go b/pkg/dialect/base/raw_test.go
index e75b262..19322e5 100644
--- a/pkg/dialect/base/raw_test.go
+++ b/pkg/dialect/base/raw_test.go
@@ -19,3 +19,55 @@ func TestRexRaw(t *testing.T) {
Expected: `[A-Z]`,
}}.Run(t)
}
+
+func TestRexRawVerbose(t *testing.T) {
+ test.RexTestCasesSlice{{
+ Name: "RawVerboseRegular",
+ Chain: []dialect.Token{
+ base.Common.RawVerbose(`.+`),
+ },
+ Expected: `.+`,
+ }, {
+ Name: "RawVerboseComment",
+ Chain: []dialect.Token{
+ base.Common.RawVerbose(`.+ # any character`),
+ },
+ Expected: `.+`,
+ }, {
+ Name: "RawVerboseMultiline",
+ Chain: []dialect.Token{
+ base.Common.RawVerbose(`
+ .+ # any character
+ \d+ # Digits
+ `),
+ },
+ Expected: `.+\d+`,
+ }, {
+ Name: "RawVerboseEscapedHashSign",
+ Chain: []dialect.Token{
+ base.Common.RawVerbose(`\#\d+ # Digits`),
+ },
+ Expected: `#\d+`,
+ }, {
+ Name: "RawVerboseEscapedHashInClass",
+ Chain: []dialect.Token{
+ base.Common.RawVerbose(`[#]\d+ # Digits`),
+ },
+ Expected: `[#]\d+`,
+ }, {
+ Name: "RawVerboseEscapedRegularExpressionInComment",
+ Chain: []dialect.Token{
+ base.Common.RawVerbose(`[#]\d+ # [Hi].+`),
+ },
+ Expected: `[#]\d+`,
+ }, {
+ Name: "RawVerboseEscapedNoCommentMultiline",
+ Chain: []dialect.Token{
+ base.Common.RawVerbose(`
+ .+
+ \d+
+ `),
+ },
+ Expected: `.+\d+`,
+ }}.Run(t)
+}
diff --git a/examples_test.go b/pkg/examples_test.go
similarity index 98%
rename from examples_test.go
rename to pkg/examples_test.go
index ba97d64..ccd115d 100644
--- a/examples_test.go
+++ b/pkg/examples_test.go
@@ -131,7 +131,13 @@ func Example_emailRawThird() {
re := rex.New(
rex.Common.Raw(`^`),
rex.Helper.NumberRange(-111, 1111),
- rex.Common.Raw(`\.[0-9]{2}$`),
+ rex.Common.RawVerbose(`
+ # RawVerbose is a synonym to Raw,
+ # but ignores comments, spaces and new lines.
+ \. # Decimal delimter.
+ [0-9]{2} # Only two digits.
+ $ # The end.
+ `),
).MustCompile()
fmt.Println("regular expression:", re.String())