├── .editorconfig ├── .eslintrc ├── .github ├── dependabot.yml └── workflows │ ├── automerge.yml │ ├── codeql-analysis.yml │ ├── gh-pages.yml │ └── test.yml ├── .gitignore ├── .mdlintrc.json ├── Gruntfile.js ├── LICENSE ├── README.md ├── VerbalExpressions.js ├── bower.json ├── dist ├── verbalexpressions.js ├── verbalexpressions.js.map ├── verbalexpressions.min.js └── verbalexpressions.min.js.map ├── docs ├── 404.md ├── Gemfile ├── Gemfile.lock ├── VerEx.md ├── VerbalExpression │ ├── capture-groups.md │ ├── constructor.md │ ├── index.md │ ├── loops.md │ ├── miscellaneous.md │ ├── modifiers.md │ ├── rules.md │ ├── special-characters.md │ └── utilities.md ├── _config.yml ├── _layouts │ └── default.html ├── assets │ └── css │ │ └── style.scss └── index.md ├── package-lock.json ├── package.json ├── test └── tests.js └── typings └── VerbalExpressions.d.ts /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | trim_trailing_whitespace = true 6 | insert_final_newline = true 7 | indent_style = space 8 | indent_size = 4 9 | charset = utf8 10 | 11 | [{package.json, package-lock.json}] 12 | indent_size = 2 13 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "airbnb", 3 | "rules": { 4 | "indent": [2, 4], 5 | "no-underscore-dangle": [2, { "allowAfterThis": true }], 6 | "no-restricted-syntax": ["error", "ForInStatement", "LabeledStatement", "WithStatement"], 7 | "newline-per-chained-call": "off", 8 | "max-len": [2, 255, 4], 9 | "no-param-reassign": 0, 10 | "spaced-comment": [2, "always", { "markers": ["/", "!"] }], 11 | "no-plusplus": 0, 12 | "operator-linebreak":"off" 13 | }, 14 | "env": { 15 | "amd": true, 16 | "node": true, 17 | "commonjs": true, 18 | "es6": true, 19 | "browser": true 20 | }, 21 | "globals": { 22 | "VerEx": true 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: npm 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | open-pull-requests-limit: 1000000 8 | - package-ecosystem: bundler 9 | directory: "/docs" 10 | schedule: 11 | interval: daily 12 | open-pull-requests-limit: 1000000 13 | -------------------------------------------------------------------------------- /.github/workflows/automerge.yml: -------------------------------------------------------------------------------- 1 | name: Dependabot auto-merge 2 | on: pull_request 3 | 4 | permissions: 5 | pull-requests: write 6 | contents: write 7 | 8 | jobs: 9 | dependabot: 10 | runs-on: ubuntu-latest 11 | if: ${{ github.actor == 'dependabot[bot]' }} 12 | steps: 13 | - name: Enable auto-merge for Dependabot PRs 14 | env: 15 | PR_URL: ${{github.event.pull_request.html_url}} 16 | GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} 17 | run: | 18 | function get_pending_jobs() { 19 | gh pr view "$PR_URL" --json statusCheckRollup --jq '.statusCheckRollup | map(select(.name != "dependabot")) | map(select(.status != "COMPLETED")).[]' 20 | } 21 | 22 | function get_failed_jobs() { 23 | gh pr view "$PR_URL" --json statusCheckRollup --jq '.statusCheckRollup | map(select(.name != "dependabot")) | map(select(.conclusion != "SUCCESS")).[]' 24 | } 25 | 26 | function wait_until_completed() { 27 | while [[ $(get_pending_jobs) ]] 28 | do 29 | sleep 5 30 | done 31 | } 32 | 33 | function fail_if_unsuccessful() { 34 | if [[ $(get_failed_jobs) ]]; then 35 | echo "Some jobs failed, unable to automerge" 36 | exit 1 37 | fi 38 | } 39 | 40 | function auto_merge() { 41 | gh pr merge --auto --rebase "$PR_URL" 42 | } 43 | 44 | wait_until_completed && \ 45 | fail_if_unsuccessful && \ 46 | auto_merge 47 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: 'CodeQL' 13 | 14 | on: 15 | push: 16 | branches: [master] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [master] 20 | schedule: 21 | - cron: '33 0 * * 1' 22 | 23 | jobs: 24 | analyze: 25 | name: Analyze 26 | runs-on: ubuntu-latest 27 | 28 | strategy: 29 | fail-fast: false 30 | matrix: 31 | language: ['javascript'] 32 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] 33 | # Learn more: 34 | # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed 35 | 36 | steps: 37 | - name: Checkout repository 38 | uses: actions/checkout@v2 39 | 40 | # Initializes the CodeQL tools for scanning. 41 | - name: Initialize CodeQL 42 | uses: github/codeql-action/init@v1 43 | with: 44 | languages: ${{ matrix.language }} 45 | # If you wish to specify custom queries, you can do so here or in a config file. 46 | # By default, queries listed here will override any specified in a config file. 47 | # Prefix the list here with "+" to use these queries and those in the config file. 48 | # queries: ./path/to/local/query, your-org/your-repo/queries@main 49 | 50 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 51 | # If this step fails, then you should remove it and run the build manually (see below) 52 | - name: Autobuild 53 | uses: github/codeql-action/autobuild@v1 54 | 55 | # ℹ️ Command-line programs to run using the OS shell. 56 | # 📚 https://git.io/JvXDl 57 | 58 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 59 | # and modify them (or add more) to build your code if your project 60 | # uses a compiled language 61 | 62 | #- run: | 63 | # make bootstrap 64 | # make release 65 | 66 | - name: Perform CodeQL Analysis 67 | uses: github/codeql-action/analyze@v1 68 | -------------------------------------------------------------------------------- /.github/workflows/gh-pages.yml: -------------------------------------------------------------------------------- 1 | name: Build docs/ folder 2 | on: pull_request 3 | jobs: 4 | test: 5 | name: Build docs/ folder 6 | runs-on: ubuntu-latest 7 | steps: 8 | - uses: actions/checkout@v2 9 | - uses: actions/setup-ruby@v1 10 | - run: | 11 | cd docs 12 | gem install bundler --version '~> 1' 13 | bundle install 14 | bundle exec jekyll build 15 | - run: | 16 | git add -A # Make sure new files are accounted 17 | git diff --exit-code --cached # Expect no changes in git 18 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Run tests 2 | on: pull_request 3 | jobs: 4 | test: 5 | name: Run tests on Node.js ${{ matrix.node-version }} 6 | runs-on: ubuntu-latest 7 | strategy: 8 | matrix: 9 | node-version: ["16", "15", "14", "13", "12"] 10 | steps: 11 | - uses: actions/checkout@v2 12 | - uses: actions/setup-node@v1 13 | with: 14 | node-version: ${{ matrix.node-version }} 15 | - run: npm ci 16 | - run: npm run test:verbose 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | .idea/ 4 | .vscode/ 5 | .nyc_output 6 | docs/_site 7 | docs/.sass-cache 8 | docs/.jekyll-metadata 9 | -------------------------------------------------------------------------------- /.mdlintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "heading-increment": true, 3 | "first-heading-h1": { "level": 1 }, 4 | "heading-style": { "style": "atx" }, 5 | "ul-style": { "style": "dash" }, 6 | "list-indent": true, 7 | "ul-start-left": true, 8 | "ul-indent": { "indent": 4 }, 9 | "no-trailing-spaces": true, 10 | "no-hard-tabs": true, 11 | "no-reversed-links": true, 12 | "no-multiple-blanks": { "maximum": 1 }, 13 | "line-length": false, 14 | "commands-show-output": true, 15 | "no-missing-space-atx": true, 16 | "no-multiple-space-atx": true, 17 | "no-missing-space-closed-atx": true, 18 | "no-multiple-space-closed-atx": true, 19 | "blanks-around-headings": true, 20 | "heading-start-left": true, 21 | "no-duplicate-heading": true, 22 | "single-h1": false, 23 | "no-trailing-punctuation": true, 24 | "ol-prefix": { "style": "ordered" }, 25 | "list-marker-space": 1, 26 | "blanks-around-fences": true, 27 | "blanks-around-lists": true, 28 | "no-inline-html": false, 29 | "no-bare-urls": true, 30 | "hr-style": { "style": "___" }, 31 | "no-emphasis-as-heading": true, 32 | "no-space-in-emphasis": true, 33 | "no-space-in-code": false, 34 | "no-space-in-links": true, 35 | "fenced-code-language": false, 36 | "first-line-h1": true, 37 | "no-empty-links": true, 38 | "no-alt-text": true 39 | } 40 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function gruntConfig(grunt) { 2 | grunt.initConfig({ 3 | pkg: grunt.file.readJSON('package.json'), 4 | 5 | eslint: { 6 | target: ['VerbalExpressions.js', 'test/tests.js', 'Gruntfile.js'], 7 | }, 8 | 9 | ava: { 10 | test: ['test/tests.js'], 11 | options: { 12 | nyc: true, 13 | }, 14 | 15 | verbose: { 16 | test: ['test/tests.js'], 17 | options: { 18 | verbose: true, 19 | nyc: true, 20 | }, 21 | }, 22 | }, 23 | 24 | babel: { 25 | options: { 26 | sourceMap: true, 27 | presets: [['@babel/preset-env', { modules: false }]], 28 | plugins: [ 29 | ['transform-builtin-extend', { globals: ['RegExp'] }], 30 | ], 31 | }, 32 | dist: { 33 | files: { 34 | 'dist/verbalexpressions.js': 'VerbalExpressions.js', 35 | }, 36 | }, 37 | }, 38 | 39 | umd: { 40 | all: { 41 | options: { 42 | src: 'dist/verbalexpressions.js', 43 | objectToExport: 'VerEx', 44 | amdModuleId: 'VerEx', 45 | globalAlias: 'VerEx', 46 | }, 47 | }, 48 | }, 49 | 50 | uglify: { 51 | options: { 52 | banner: 53 | '/*!\n' + 54 | '* <%= pkg.name %> JavaScript Library v<%= pkg.version %>\n' + 55 | '* <%= pkg.homepage %>\n' + 56 | '*\n' + 57 | '* Released under the <%= pkg.license %> license\n' + 58 | '*/\n', 59 | sourceMap: true, 60 | }, 61 | dist: { 62 | files: { 63 | 'dist/verbalexpressions.min.js': [ 64 | 'dist/verbalexpressions.js', 65 | ], 66 | }, 67 | }, 68 | }, 69 | 70 | sourcemap_localize: { 71 | options: { 72 | localize_to: '..', 73 | }, 74 | build: { 75 | files: { 76 | src: ['dist/*.min.js.map'], 77 | }, 78 | }, 79 | }, 80 | 81 | markdownlint: { 82 | options: { 83 | config: grunt.file.readJSON('.mdlintrc.json'), 84 | }, 85 | src: ['README.md', 'docs/*.md', 'docs/VerbalExpression/*.md'], 86 | }, 87 | }); 88 | 89 | grunt.loadNpmTasks('grunt-eslint'); 90 | grunt.loadNpmTasks('grunt-ava'); 91 | grunt.loadNpmTasks('grunt-babel'); 92 | grunt.loadNpmTasks('grunt-umd'); 93 | grunt.loadNpmTasks('grunt-contrib-uglify'); 94 | grunt.loadNpmTasks('grunt-sourcemap-localize'); 95 | grunt.loadNpmTasks('grunt-markdownlint'); 96 | 97 | grunt.registerTask('default', ['test']); 98 | grunt.registerTask('test', [ 99 | 'compile', 100 | 'eslint', 101 | 'markdownlint', 102 | 'ava:test', 103 | ]); 104 | grunt.registerTask('test:verbose', ['compile', 'eslint', 'ava:verbose']); 105 | grunt.registerTask('compile', ['babel', 'umd:all']); 106 | grunt.registerTask('build', [ 107 | 'compile', 108 | 'ava:test', 109 | 'uglify', 110 | 'sourcemap_localize', 111 | ]); 112 | }; 113 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 jehna 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # VerbalExpressions 2 | 3 | [![Build Status](https://travis-ci.org/VerbalExpressions/JSVerbalExpressions.svg)](https://travis-ci.org/VerbalExpressions/JSVerbalExpressions) 4 | [![Latest Version](https://img.shields.io/npm/v/verbal-expressions.svg)](https://www.npmjs.com/package/verbal-expressions) 5 | [![jsDelivr](https://img.shields.io/badge/dynamic/json.svg?label=jsDelivr&url=https%3A%2F%2Fdata.jsdelivr.com%2Fv1%2Fpackage%2Fnpm%2Fverbal-expressions&query=%24..tags.latest&colorB=blue&prefix=v)](https://www.jsdelivr.com/package/npm/verbal-expressions) 6 | [![License](https://img.shields.io/github/license/VerbalExpressions/JSVerbalExpressions.svg)](LICENSE) 7 | 8 | ## JavaScript Regular Expressions made easy 9 | 10 | VerbalExpressions is a JavaScript library that helps construct difficult regular expressions. 11 | 12 | ## How to get started 13 | 14 | ### In the browser 15 | 16 | ```html 17 | 18 | ``` 19 | 20 | Or use the [jsDelivr CDN](https://www.jsdelivr.com/package/npm/verbal-expressions). 21 | 22 | ### On the server (node.js) 23 | 24 | Install: 25 | 26 | ```sh 27 | npm install verbal-expressions 28 | ``` 29 | 30 | Require: 31 | 32 | ```js 33 | const VerEx = require('verbal-expressions'); 34 | ``` 35 | 36 | Or use ES6's `import`: 37 | 38 | ```js 39 | import VerEx from 'verbal-expressions'; 40 | ``` 41 | 42 | ## Running tests 43 | 44 | ```sh 45 | npm test 46 | ``` 47 | 48 | (or) 49 | 50 | ```sh 51 | npm run test:verbose 52 | ``` 53 | 54 | ## Creating a minified version 55 | 56 | ```sh 57 | npm run build 58 | ``` 59 | 60 | This will run [Babel](https://babeljs.io) on `VerbalExpressions.js` and output the result to `dist/verbalexpressions.js`. A minified version of the same will also be written to `dist/verbalexpressions.min.js`. 61 | 62 | A source map will also be created in `dist`, so you can use the original "un-babelified", unminified source file for debugging purposes. 63 | 64 | ## Building the docs/ folder 65 | 66 | The `docs/` folder uses Jekyll for building the static HTML and is hosted at 67 | gh-pages. 68 | 69 | To install the Ruby dependencies, run: 70 | 71 | ``` 72 | cd docs/ 73 | bundle install 74 | ``` 75 | 76 | This installs all needed Ruby dependencies locally 77 | 78 | After you've installed dependencies, you can run: 79 | 80 | ``` 81 | bundle exec jekyll build 82 | ``` 83 | 84 | This builds all static files to `docs/_site/` folder. 85 | 86 | If you want to develop the files locally, you can run: 87 | 88 | ``` 89 | bundle exec jekyll serve 90 | ``` 91 | 92 | This starts a local development web server and starts watching your files for 93 | changes. 94 | 95 | ## API documentation 96 | 97 | You can find the API documentation at [verbalexpressions.github.io/JSVerbalExpressions](https://verbalexpressions.github.io/JSVerbalExpressions). You can find the source code for the docs in [`docs`](docs/). 98 | 99 | ## Examples 100 | 101 | Here are some simple examples to give an idea of how VerbalExpressions works: 102 | 103 | ### Testing if we have a valid URL 104 | 105 | ```js 106 | // Create an example of how to test for correctly formed URLs 107 | const tester = VerEx() 108 | .startOfLine() 109 | .then('http') 110 | .maybe('s') 111 | .then('://') 112 | .maybe('www.') 113 | .anythingBut(' ') 114 | .endOfLine(); 115 | 116 | // Create an example URL 117 | const testMe = 'https://www.google.com'; 118 | 119 | // Use RegExp object's native test() function 120 | if (tester.test(testMe)) { 121 | alert('We have a correct URL'); // This output will fire 122 | } else { 123 | alert('The URL is incorrect'); 124 | } 125 | 126 | console.log(tester); // Outputs the actual expression used: /^(http)(s)?(\:\/\/)(www\.)?([^\ ]*)$/ 127 | ``` 128 | 129 | ### Replacing strings 130 | 131 | ```js 132 | // Create a test string 133 | const replaceMe = 'Replace bird with a duck'; 134 | 135 | // Create an expression that seeks for word "bird" 136 | const expression = VerEx().find('bird'); 137 | 138 | // Execute the expression like a normal RegExp object 139 | const result = expression.replace(replaceMe, 'duck'); 140 | 141 | // Outputs "Replace duck with a duck" 142 | alert(result); 143 | ``` 144 | 145 | ### Shorthand for string replace 146 | 147 | ```js 148 | const result = VerEx().find('red').replace('We have a red house', 'blue'); 149 | 150 | // Outputs "We have a blue house" 151 | alert(result); 152 | ``` 153 | 154 | ## Contributions 155 | 156 | Pull requests are warmly welcome! 157 | 158 | Clone the repo and fork: 159 | 160 | ```sh 161 | git clone https://github.com/VerbalExpressions/JSVerbalExpressions.git 162 | ``` 163 | 164 | ### Style guide 165 | 166 | The [Airbnb](https://github.com/airbnb/javascript) style guide is loosely used as a basis for creating clean and readable JavaScript code. Check [`.eslintrc`](.eslintrc). 167 | 168 | Check out these slide decks for handy Github & git tips: 169 | 170 | - [Git and Github Secrets](https://zachholman.com/talk/git-github-secrets/) 171 | - [More Git and Github Secrets](https://zachholman.com/talk/more-git-and-github-secrets/) 172 | 173 | ## Tools 174 | 175 | - - it's a wrapper of JSVerbalExpressions; users can write down the code and compile to regex 176 | - - JSBin Playground 177 | 178 | ## Other Implementations 179 | 180 | You can see an up to date list of all ports on [VerbalExpressions.github.io](https://VerbalExpressions.github.io). 181 | 182 | - [Ruby](https://github.com/ryan-endacott/verbal_expressions) 183 | - [C#](https://github.com/VerbalExpressions/CSharpVerbalExpressions) 184 | - [Python](https://github.com/VerbalExpressions/PythonVerbalExpressions) 185 | - [Java](https://github.com/VerbalExpressions/JavaVerbalExpressions) 186 | - [Groovy](https://github.com/VerbalExpressions/GroovyVerbalExpressions) 187 | - [PHP](https://github.com/VerbalExpressions/PHPVerbalExpressions) 188 | - [Haskell](https://github.com/VerbalExpressions/HaskellVerbalExpressions) 189 | - [Haxe](https://github.com/VerbalExpressions/HaxeVerbalExpressions) 190 | - [C++](https://github.com/VerbalExpressions/CppVerbalExpressions) 191 | - [Objective-C](https://github.com/VerbalExpressions/ObjectiveCVerbalExpressions) 192 | - [Perl](https://github.com/VerbalExpressions/PerlVerbalExpressions) 193 | - [Swift](https://github.com/VerbalExpressions/SwiftVerbalExpressions) 194 | 195 | If you would like to contribute another port (which would be awesome!), please [open an issue](https://github.com/VerbalExpressions/implementation/issues/new) specifying the language in the [VerbalExpressions/implementation repo](https://github.com/VerbalExpressions/implementation/issues). Please don't open PRs for other languages against this repo. 196 | 197 | ### Similar projects 198 | 199 | Here's a list of other similar projects that implement regular expression 200 | builders: 201 | 202 | - https://github.com/MaxArt2501/re-build 203 | - https://github.com/mathiasbynens/regenerate -------------------------------------------------------------------------------- /VerbalExpressions.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @file VerbalExpressions JavaScript Library 3 | * @version 0.3.0 4 | * @license MIT 5 | * 6 | * @see https://github.com/VerbalExpressions/JSVerbalExpressions 7 | */ 8 | 9 | /** 10 | * Define the VerbalExpression class 11 | * 12 | * @class VerbalExpression 13 | * @extends {RegExp} 14 | */ 15 | class VerbalExpression extends RegExp { 16 | /** 17 | * Creates an instance of VerbalExpression. 18 | * @constructor 19 | * @alias VerEx 20 | * @memberof VerbalExpression 21 | */ 22 | constructor() { 23 | // Call the `RegExp` constructor so that `this` can be used 24 | super('', 'gm'); 25 | 26 | // Variables to hold the expression construction in order 27 | this._prefixes = ''; 28 | this._source = ''; 29 | this._suffixes = ''; 30 | this._modifiers = 'gm'; // 'global, multiline' matching by default 31 | } 32 | 33 | // Utility // 34 | 35 | /** 36 | * Escape meta-characters in the parameter and make it safe for adding to the expression 37 | * @static 38 | * @param {(string|RegExp|number)} value object to sanitize 39 | * @returns {string} sanitized value 40 | * @memberof VerbalExpression 41 | */ 42 | static sanitize(value) { 43 | if (value instanceof RegExp) { 44 | return value.source; 45 | } 46 | 47 | if (typeof value === 'number') { 48 | return value; 49 | } 50 | 51 | if (typeof value !== 'string') { 52 | return ''; 53 | } 54 | 55 | // Regular expression to match meta characters 56 | // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/regexp 57 | const toEscape = /([\].|*?+(){}^$\\:=[])/g; 58 | 59 | // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/lastMatch 60 | const lastMatch = '$&'; 61 | 62 | // Escape meta characters 63 | return value.replace(toEscape, `\\${lastMatch}`); 64 | } 65 | 66 | /** 67 | * Add stuff to the expression and compile the new expression so it's ready to be used. 68 | * @param {(string|number)} [value=''] stuff to add 69 | * @returns {VerbalExpression} recompiled instance of VerbalExpression 70 | * @memberof VerbalExpression 71 | */ 72 | add(value = '') { 73 | this._source += value; 74 | const pattern = this._prefixes + this._source + this._suffixes; 75 | 76 | this.compile(pattern, this._modifiers); 77 | 78 | return this; 79 | } 80 | 81 | // Rules // 82 | 83 | /** 84 | * Control start-of-line matching 85 | * @param {boolean} [enable=true] whether to enable this behaviour 86 | * @returns {VerbalExpression} recompiled instance of VerbalExpression 87 | * @memberof VerbalExpression 88 | */ 89 | startOfLine(enable = true) { 90 | this._prefixes = enable ? '^' : ''; 91 | return this.add(); 92 | } 93 | 94 | /** 95 | * Control end-of-line matching 96 | * @param {boolean} [enable=true] whether to enable this behaviour 97 | * @returns {VerbalExpression} recompiled instance of VerbalExpression 98 | * @memberof VerbalExpression 99 | */ 100 | endOfLine(enable = true) { 101 | this._suffixes = enable ? '$' : ''; 102 | return this.add(); 103 | } 104 | 105 | /** 106 | * Look for the value passed 107 | * @param {(string|RegExp|number)} value value to find 108 | * @returns {VerbalExpression} recompiled instance of VerbalExpression 109 | * @memberof VerbalExpression 110 | */ 111 | then(value) { 112 | value = VerbalExpression.sanitize(value); 113 | return this.add(`(?:${value})`); 114 | } 115 | 116 | /** 117 | * Alias for then() to allow for readable syntax when then() is the first method in the chain. 118 | * @param {(string|RegExp|numer)} value value to find 119 | * @returns {VerbalExpression} recompiled instance of VerbalExpression 120 | * @memberof VerbalExpression 121 | */ 122 | find(value) { 123 | return this.then(value); 124 | } 125 | 126 | /** 127 | * Add optional values 128 | * @param {(string|RegExp|number)} value value to find 129 | * @returns {VerbalExpression} recompiled instance of VerbalExpression 130 | * @memberof VerbalExpression 131 | */ 132 | maybe(value) { 133 | value = VerbalExpression.sanitize(value); 134 | return this.add(`(?:${value})?`); 135 | } 136 | 137 | /** 138 | * Add alternative expressions 139 | * @param {(string|RegExp|number)} value value to find 140 | * @returns {VerbalExpression} recompiled instance of VerbalExpression 141 | * @memberof VerbalExpression 142 | */ 143 | or(value) { 144 | this._prefixes += '(?:'; 145 | this._suffixes = `)${this._suffixes}`; 146 | 147 | this.add(')|(?:'); 148 | 149 | if (value) { 150 | this.then(value); 151 | } 152 | 153 | return this; 154 | } 155 | 156 | /** 157 | * Any character any number of times 158 | * @returns {VerbalExpression} recompiled instance of VerbalExpression 159 | * @memberof VerbalExpression 160 | */ 161 | anything() { 162 | return this.add('(?:.*)'); 163 | } 164 | 165 | /** 166 | * Anything but these characters 167 | * @param {(string|number|string[]|number[])} value characters to not match 168 | * @returns {VerbalExpression} recompiled instance of VerbalExpression 169 | * @memberof VerbalExpression 170 | */ 171 | anythingBut(value) { 172 | if (Array.isArray(value)) { 173 | value = value.join(''); 174 | } 175 | 176 | value = VerbalExpression.sanitize(value); 177 | return this.add(`(?:[^${value}]*)`); 178 | } 179 | 180 | /** 181 | * Any character(s) at least once 182 | * @returns {VerbalExpression} recompiled instance of VerbalExpression 183 | * @memberof VerbalExpression 184 | */ 185 | something() { 186 | return this.add('(?:.+)'); 187 | } 188 | 189 | /** 190 | * Any character at least one time except for these characters 191 | * @param {(string|number|string[]|number[])} value characters to not match 192 | * @returns {VerbalExpression} recompiled instance of VerbalExpression 193 | * @memberof VerbalExpression 194 | */ 195 | somethingBut(value) { 196 | if (Array.isArray(value)) { 197 | value = value.join(''); 198 | } 199 | 200 | value = VerbalExpression.sanitize(value); 201 | return this.add(`(?:[^${value}]+)`); 202 | } 203 | 204 | /** 205 | * Match any of the given characters 206 | * @param {(string|number|string[]|number[])} value characters to match 207 | * @returns {VerbalExpression} recompiled instance of VerbalExpression 208 | * @memberof VerbalExpression 209 | */ 210 | anyOf(value) { 211 | if (Array.isArray(value)) { 212 | value = value.join(''); 213 | } 214 | 215 | value = VerbalExpression.sanitize(value); 216 | return this.add(`[${value}]`); 217 | } 218 | 219 | /** 220 | * Shorthand for anyOf(value) 221 | * @param {string|number} value value to find 222 | * @returns {VerbalExpression} recompiled instance of VerbalExpression 223 | * @memberof VerbalExpression 224 | */ 225 | any(value) { 226 | return this.anyOf(value); 227 | } 228 | 229 | /** 230 | * Ensure that the parameter does not follow 231 | * @param {string|number} value 232 | * @returns {VerbalExpression} recompiled instance of VerbalExpression 233 | * @memberof VerbalExpression 234 | */ 235 | not(value) { 236 | value = VerbalExpression.sanitize(value); 237 | this.add(`(?!${value})`); 238 | 239 | return this; 240 | } 241 | 242 | /** 243 | * Matching any character within a range of characters 244 | * Usage: .range( from, to [, from, to ... ] ) 245 | * @param {...string} ranges characters denoting beginning and ending of ranges 246 | * @returns {VerbalExpression} recompiled instance of VerbalExpression 247 | * @memberof VerbalExpression 248 | */ 249 | range(...ranges) { 250 | let value = ''; 251 | 252 | for (let i = 1; i < ranges.length; i += 2) { 253 | const from = VerbalExpression.sanitize(ranges[i - 1]); 254 | const to = VerbalExpression.sanitize(ranges[i]); 255 | 256 | value += `${from}-${to}`; 257 | } 258 | 259 | return this.add(`[${value}]`); 260 | } 261 | 262 | // Special characters // 263 | 264 | /** 265 | * Match a Line break 266 | * @returns {VerbalExpression} recompiled instance of VerbalExpression 267 | * @memberof VerbalExpression 268 | */ 269 | lineBreak() { 270 | return this.add('(?:\\r\\n|\\r|\\n)'); // Unix(LF) + Windows(CRLF) 271 | } 272 | 273 | /** 274 | * A shorthand for lineBreak() for html-minded users 275 | * @returns {VerbalExpression} recompiled instance of VerbalExpression 276 | * @memberof VerbalExpression 277 | */ 278 | br() { 279 | return this.lineBreak(); 280 | } 281 | 282 | /** 283 | * Match a tab character 284 | * @returns {VerbalExpression} recompiled instance of VerbalExpression 285 | * @memberof VerbalExpression 286 | */ 287 | tab() { 288 | return this.add('\\t'); 289 | } 290 | 291 | /** 292 | * Match any alphanumeric 293 | * @returns {VerbalExpression} recompiled instance of VerbalExpression 294 | * @memberof VerbalExpression 295 | */ 296 | word() { 297 | return this.add('\\w+'); 298 | } 299 | 300 | /** 301 | * Match a single digit 302 | * @returns {VerbalExpression} recompiled instance of VerbalExpression 303 | * @memberof VerbalExpression 304 | */ 305 | digit() { 306 | return this.add('\\d'); 307 | } 308 | 309 | /** 310 | * Match a single whitespace 311 | * @returns {VerbalExpression} recompiled instance of VerbalExpression 312 | * @memberof VerbalExpression 313 | */ 314 | whitespace() { 315 | return this.add('\\s'); 316 | } 317 | 318 | // Modifiers // 319 | 320 | /** 321 | * Add a regex modifier/flag 322 | * @param {string} modifier modifier to add 323 | * @returns {VerbalExpression} recompiled instance of VerbalExpression 324 | * @memberof VerbalExpression 325 | */ 326 | addModifier(modifier) { 327 | if (!this._modifiers.includes(modifier)) { 328 | this._modifiers += modifier; 329 | } 330 | 331 | return this.add(); 332 | } 333 | 334 | /** 335 | * Remove modifier 336 | * @param {string} modifier modifier to remove 337 | * @returns {VerbalExpression} recompiled instance of VerbalExpression 338 | * @memberof VerbalExpression 339 | */ 340 | removeModifier(modifier) { 341 | this._modifiers = this._modifiers.replace(modifier, ''); 342 | return this.add(); 343 | } 344 | 345 | /** 346 | * Control case-insensitive matching 347 | * @param {boolean} [enable=true] whether to enable this behaviour 348 | * @returns {VerbalExpression} recompiled instance of VerbalExpression 349 | * @memberof VerbalExpression 350 | */ 351 | withAnyCase(enable = true) { 352 | return enable ? this.addModifier('i') : this.removeModifier('i'); 353 | } 354 | 355 | /** 356 | * Default behaviour is with "g" modifier, so we can turn this another way around than other modifiers 357 | * @param {boolean} [enable=true] whether to enable this behaviour 358 | * @returns {VerbalExpression} recompiled instance of VerbalExpression 359 | * @memberof VerbalExpression 360 | */ 361 | stopAtFirst(enable = true) { 362 | return enable ? this.removeModifier('g') : this.addModifier('g'); 363 | } 364 | 365 | /** 366 | * Control the multiline modifier 367 | * @param {boolean} [enable=true] whether to enable this behaviour 368 | * @returns {VerbalExpression} recompiled instance of VerbalExpression 369 | * @memberof VerbalExpression 370 | */ 371 | searchOneLine(enable = true) { 372 | return enable ? this.removeModifier('m') : this.addModifier('m'); 373 | } 374 | 375 | // Loops // 376 | 377 | /** 378 | * Repeat the previous item exactly n times or between n and m times 379 | * @returns {VerbalExpression} recompiled instance of VerbalExpression 380 | * @memberof VerbalExpression 381 | */ 382 | repeatPrevious(...quantity) { 383 | const isInteger = /\d+/; 384 | const values = quantity.filter((argument) => isInteger.test(argument)); 385 | 386 | if (values.length === 0 || values.length > 2) { 387 | return this; 388 | } 389 | 390 | this.add(`{${values.join(',')}}`); 391 | 392 | return this; 393 | } 394 | 395 | /** 396 | * Repeat the previous at least once 397 | * @returns {VerbalExpression} recompiled instance of VerbalExpression 398 | * @memberof VerbalExpression 399 | */ 400 | oneOrMore() { 401 | return this.add('+'); 402 | } 403 | 404 | /** 405 | * Match the value zero or more times 406 | * @param {string} value value to find 407 | * @param {integer} [lower] minimum number of times the value should be repeated 408 | * @param {integer} [upper] maximum number of times the value should be repeated 409 | * @returns {VerbalExpression} recompiled instance of VerbalExpression 410 | * @memberof VerbalExpression 411 | */ 412 | multiple(value, lower, upper) { 413 | if (value !== undefined) { 414 | value = VerbalExpression.sanitize(value); 415 | this.add(`(?:${value})`); 416 | } 417 | 418 | if (lower === undefined && upper === undefined) { 419 | this.add('*'); // Any number of times 420 | } else if (lower !== undefined && upper === undefined) { 421 | this.add(`{${lower},}`); 422 | } else if (lower !== undefined && upper !== undefined) { 423 | this.add(`{${lower},${upper}}`); 424 | } 425 | 426 | return this; 427 | } 428 | 429 | // Capture groups // 430 | 431 | /** 432 | * Starts a capturing group 433 | * @returns {VerbalExpression} recompiled instance of VerbalExpression 434 | * @memberof VerbalExpression 435 | */ 436 | beginCapture() { 437 | // Add the end of the capture group to the suffixes temporarily so that compilation continues to work 438 | this._suffixes += ')'; 439 | return this.add('('); 440 | } 441 | 442 | /** 443 | * Ends a capturing group 444 | * @returns {VerbalExpression} recompiled instance of VerbalExpression 445 | * @memberof VerbalExpression 446 | */ 447 | endCapture() { 448 | // Remove the last parenthesis from the _suffixes and add it to the regex 449 | this._suffixes = this._suffixes.slice(0, -1); 450 | return this.add(')'); 451 | } 452 | 453 | // Miscellaneous // 454 | 455 | /** 456 | * Shorthand function for the string.replace function to allow for a more logical flow 457 | * @param {string} source string to search for 458 | * @param {string} value value to replace with 459 | * @returns {VerbalExpression} recompiled instance of VerbalExpression 460 | * @memberof VerbalExpression 461 | */ 462 | replace(source, value) { 463 | source = source.toString(); 464 | return source.replace(this, value); 465 | } 466 | 467 | /** 468 | * Convert to RegExp object 469 | * @returns {RegExp} equivalent RegExp instance 470 | * @memberof VerbalExpression 471 | */ 472 | toRegExp() { 473 | const components = this.toString().match(/\/(.*)\/([gimuy]+)?/); 474 | const pattern = components[1]; 475 | const flags = components[2]; 476 | 477 | return new RegExp(pattern, flags); 478 | } 479 | } 480 | 481 | /** 482 | * Return a new instance of `VerbalExpression` 483 | * @export 484 | * @returns {VerbalExpression} new instance 485 | */ 486 | function VerEx() { // eslint-disable-line no-unused-vars 487 | const instance = new VerbalExpression(); 488 | instance.sanitize = VerbalExpression.sanitize; 489 | return instance; 490 | } 491 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "verbal-expressions", 3 | "description": "JavaScript Regular expressions made easy", 4 | "keywords": [ "regular expressions", "regex" ], 5 | "main": "dist/verbalexpressions.js", 6 | "license": "MIT", 7 | "ignore": [ 8 | "**/.*", 9 | "node_modules", 10 | "bower_components", 11 | "test", 12 | "tests", 13 | "Gruntfile.js", 14 | "package.json", 15 | "bower.json" 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /dist/verbalexpressions.js: -------------------------------------------------------------------------------- 1 | (function (root, factory) { 2 | if (root === undefined && window !== undefined) root = window; 3 | if (typeof define === 'function' && define.amd) { 4 | // AMD. Register as an anonymous module unless amdModuleId is set 5 | define('VerEx', [], function () { 6 | return (root['VerEx'] = factory()); 7 | }); 8 | } else if (typeof module === 'object' && module.exports) { 9 | // Node. Does not work with strict CommonJS, but 10 | // only CommonJS-like environments that support module.exports, 11 | // like Node. 12 | module.exports = factory(); 13 | } else { 14 | root['VerEx'] = factory(); 15 | } 16 | }(this, function () { 17 | 18 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); 19 | 20 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 21 | 22 | function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } 23 | 24 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 25 | 26 | function _extendableBuiltin(cls) { 27 | function ExtendableBuiltin() { 28 | var instance = Reflect.construct(cls, Array.from(arguments)); 29 | Object.setPrototypeOf(instance, Object.getPrototypeOf(this)); 30 | return instance; 31 | } 32 | 33 | ExtendableBuiltin.prototype = Object.create(cls.prototype, { 34 | constructor: { 35 | value: cls, 36 | enumerable: false, 37 | writable: true, 38 | configurable: true 39 | } 40 | }); 41 | 42 | if (Object.setPrototypeOf) { 43 | Object.setPrototypeOf(ExtendableBuiltin, cls); 44 | } else { 45 | ExtendableBuiltin.__proto__ = cls; 46 | } 47 | 48 | return ExtendableBuiltin; 49 | } 50 | 51 | /** 52 | * @file VerbalExpressions JavaScript Library 53 | * @version 0.3.0 54 | * @license MIT 55 | * 56 | * @see https://github.com/VerbalExpressions/JSVerbalExpressions 57 | */ 58 | 59 | /** 60 | * Define the VerbalExpression class 61 | * 62 | * @class VerbalExpression 63 | * @extends {RegExp} 64 | */ 65 | var VerbalExpression = function (_extendableBuiltin2) { 66 | _inherits(VerbalExpression, _extendableBuiltin2); 67 | 68 | /** 69 | * Creates an instance of VerbalExpression. 70 | * @constructor 71 | * @alias VerEx 72 | * @memberof VerbalExpression 73 | */ 74 | function VerbalExpression() { 75 | _classCallCheck(this, VerbalExpression); 76 | 77 | // Variables to hold the expression construction in order 78 | var _this = _possibleConstructorReturn(this, (VerbalExpression.__proto__ || Object.getPrototypeOf(VerbalExpression)).call(this, '', 'gm')); 79 | // Call the `RegExp` constructor so that `this` can be used 80 | 81 | 82 | _this._prefixes = ''; 83 | _this._source = ''; 84 | _this._suffixes = ''; 85 | _this._modifiers = 'gm'; // 'global, multiline' matching by default 86 | return _this; 87 | } 88 | 89 | // Utility // 90 | 91 | /** 92 | * Escape meta-characters in the parameter and make it safe for adding to the expression 93 | * @static 94 | * @param {(string|RegExp|number)} value object to sanitize 95 | * @returns {string} sanitized value 96 | * @memberof VerbalExpression 97 | */ 98 | 99 | 100 | _createClass(VerbalExpression, [{ 101 | key: 'add', 102 | 103 | 104 | /** 105 | * Add stuff to the expression and compile the new expression so it's ready to be used. 106 | * @param {(string|number)} [value=''] stuff to add 107 | * @returns {VerbalExpression} recompiled instance of VerbalExpression 108 | * @memberof VerbalExpression 109 | */ 110 | value: function add() { 111 | var value = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ''; 112 | 113 | this._source += value; 114 | var pattern = this._prefixes + this._source + this._suffixes; 115 | 116 | this.compile(pattern, this._modifiers); 117 | 118 | return this; 119 | } 120 | 121 | // Rules // 122 | 123 | /** 124 | * Control start-of-line matching 125 | * @param {boolean} [enable=true] whether to enable this behaviour 126 | * @returns {VerbalExpression} recompiled instance of VerbalExpression 127 | * @memberof VerbalExpression 128 | */ 129 | 130 | }, { 131 | key: 'startOfLine', 132 | value: function startOfLine() { 133 | var enable = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true; 134 | 135 | this._prefixes = enable ? '^' : ''; 136 | return this.add(); 137 | } 138 | 139 | /** 140 | * Control end-of-line matching 141 | * @param {boolean} [enable=true] whether to enable this behaviour 142 | * @returns {VerbalExpression} recompiled instance of VerbalExpression 143 | * @memberof VerbalExpression 144 | */ 145 | 146 | }, { 147 | key: 'endOfLine', 148 | value: function endOfLine() { 149 | var enable = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true; 150 | 151 | this._suffixes = enable ? '$' : ''; 152 | return this.add(); 153 | } 154 | 155 | /** 156 | * Look for the value passed 157 | * @param {(string|RegExp|number)} value value to find 158 | * @returns {VerbalExpression} recompiled instance of VerbalExpression 159 | * @memberof VerbalExpression 160 | */ 161 | 162 | }, { 163 | key: 'then', 164 | value: function then(value) { 165 | value = VerbalExpression.sanitize(value); 166 | return this.add('(?:' + value + ')'); 167 | } 168 | 169 | /** 170 | * Alias for then() to allow for readable syntax when then() is the first method in the chain. 171 | * @param {(string|RegExp|numer)} value value to find 172 | * @returns {VerbalExpression} recompiled instance of VerbalExpression 173 | * @memberof VerbalExpression 174 | */ 175 | 176 | }, { 177 | key: 'find', 178 | value: function find(value) { 179 | return this.then(value); 180 | } 181 | 182 | /** 183 | * Add optional values 184 | * @param {(string|RegExp|number)} value value to find 185 | * @returns {VerbalExpression} recompiled instance of VerbalExpression 186 | * @memberof VerbalExpression 187 | */ 188 | 189 | }, { 190 | key: 'maybe', 191 | value: function maybe(value) { 192 | value = VerbalExpression.sanitize(value); 193 | return this.add('(?:' + value + ')?'); 194 | } 195 | 196 | /** 197 | * Add alternative expressions 198 | * @param {(string|RegExp|number)} value value to find 199 | * @returns {VerbalExpression} recompiled instance of VerbalExpression 200 | * @memberof VerbalExpression 201 | */ 202 | 203 | }, { 204 | key: 'or', 205 | value: function or(value) { 206 | this._prefixes += '(?:'; 207 | this._suffixes = ')' + this._suffixes; 208 | 209 | this.add(')|(?:'); 210 | 211 | if (value) { 212 | this.then(value); 213 | } 214 | 215 | return this; 216 | } 217 | 218 | /** 219 | * Any character any number of times 220 | * @returns {VerbalExpression} recompiled instance of VerbalExpression 221 | * @memberof VerbalExpression 222 | */ 223 | 224 | }, { 225 | key: 'anything', 226 | value: function anything() { 227 | return this.add('(?:.*)'); 228 | } 229 | 230 | /** 231 | * Anything but these characters 232 | * @param {(string|number|string[]|number[])} value characters to not match 233 | * @returns {VerbalExpression} recompiled instance of VerbalExpression 234 | * @memberof VerbalExpression 235 | */ 236 | 237 | }, { 238 | key: 'anythingBut', 239 | value: function anythingBut(value) { 240 | if (Array.isArray(value)) { 241 | value = value.join(''); 242 | } 243 | 244 | value = VerbalExpression.sanitize(value); 245 | return this.add('(?:[^' + value + ']*)'); 246 | } 247 | 248 | /** 249 | * Any character(s) at least once 250 | * @returns {VerbalExpression} recompiled instance of VerbalExpression 251 | * @memberof VerbalExpression 252 | */ 253 | 254 | }, { 255 | key: 'something', 256 | value: function something() { 257 | return this.add('(?:.+)'); 258 | } 259 | 260 | /** 261 | * Any character at least one time except for these characters 262 | * @param {(string|number|string[]|number[])} value characters to not match 263 | * @returns {VerbalExpression} recompiled instance of VerbalExpression 264 | * @memberof VerbalExpression 265 | */ 266 | 267 | }, { 268 | key: 'somethingBut', 269 | value: function somethingBut(value) { 270 | if (Array.isArray(value)) { 271 | value = value.join(''); 272 | } 273 | 274 | value = VerbalExpression.sanitize(value); 275 | return this.add('(?:[^' + value + ']+)'); 276 | } 277 | 278 | /** 279 | * Match any of the given characters 280 | * @param {(string|number|string[]|number[])} value characters to match 281 | * @returns {VerbalExpression} recompiled instance of VerbalExpression 282 | * @memberof VerbalExpression 283 | */ 284 | 285 | }, { 286 | key: 'anyOf', 287 | value: function anyOf(value) { 288 | if (Array.isArray(value)) { 289 | value = value.join(''); 290 | } 291 | 292 | value = VerbalExpression.sanitize(value); 293 | return this.add('[' + value + ']'); 294 | } 295 | 296 | /** 297 | * Shorthand for anyOf(value) 298 | * @param {string|number} value value to find 299 | * @returns {VerbalExpression} recompiled instance of VerbalExpression 300 | * @memberof VerbalExpression 301 | */ 302 | 303 | }, { 304 | key: 'any', 305 | value: function any(value) { 306 | return this.anyOf(value); 307 | } 308 | 309 | /** 310 | * Ensure that the parameter does not follow 311 | * @param {string|number} value 312 | * @returns {VerbalExpression} recompiled instance of VerbalExpression 313 | * @memberof VerbalExpression 314 | */ 315 | 316 | }, { 317 | key: 'not', 318 | value: function not(value) { 319 | value = VerbalExpression.sanitize(value); 320 | this.add('(?!' + value + ')'); 321 | 322 | return this; 323 | } 324 | 325 | /** 326 | * Matching any character within a range of characters 327 | * Usage: .range( from, to [, from, to ... ] ) 328 | * @param {...string} ranges characters denoting beginning and ending of ranges 329 | * @returns {VerbalExpression} recompiled instance of VerbalExpression 330 | * @memberof VerbalExpression 331 | */ 332 | 333 | }, { 334 | key: 'range', 335 | value: function range() { 336 | var value = ''; 337 | 338 | for (var i = 1; i < arguments.length; i += 2) { 339 | var from = VerbalExpression.sanitize(arguments.length <= i - 1 ? undefined : arguments[i - 1]); 340 | var to = VerbalExpression.sanitize(arguments.length <= i ? undefined : arguments[i]); 341 | 342 | value += from + '-' + to; 343 | } 344 | 345 | return this.add('[' + value + ']'); 346 | } 347 | 348 | // Special characters // 349 | 350 | /** 351 | * Match a Line break 352 | * @returns {VerbalExpression} recompiled instance of VerbalExpression 353 | * @memberof VerbalExpression 354 | */ 355 | 356 | }, { 357 | key: 'lineBreak', 358 | value: function lineBreak() { 359 | return this.add('(?:\\r\\n|\\r|\\n)'); // Unix(LF) + Windows(CRLF) 360 | } 361 | 362 | /** 363 | * A shorthand for lineBreak() for html-minded users 364 | * @returns {VerbalExpression} recompiled instance of VerbalExpression 365 | * @memberof VerbalExpression 366 | */ 367 | 368 | }, { 369 | key: 'br', 370 | value: function br() { 371 | return this.lineBreak(); 372 | } 373 | 374 | /** 375 | * Match a tab character 376 | * @returns {VerbalExpression} recompiled instance of VerbalExpression 377 | * @memberof VerbalExpression 378 | */ 379 | 380 | }, { 381 | key: 'tab', 382 | value: function tab() { 383 | return this.add('\\t'); 384 | } 385 | 386 | /** 387 | * Match any alphanumeric 388 | * @returns {VerbalExpression} recompiled instance of VerbalExpression 389 | * @memberof VerbalExpression 390 | */ 391 | 392 | }, { 393 | key: 'word', 394 | value: function word() { 395 | return this.add('\\w+'); 396 | } 397 | 398 | /** 399 | * Match a single digit 400 | * @returns {VerbalExpression} recompiled instance of VerbalExpression 401 | * @memberof VerbalExpression 402 | */ 403 | 404 | }, { 405 | key: 'digit', 406 | value: function digit() { 407 | return this.add('\\d'); 408 | } 409 | 410 | /** 411 | * Match a single whitespace 412 | * @returns {VerbalExpression} recompiled instance of VerbalExpression 413 | * @memberof VerbalExpression 414 | */ 415 | 416 | }, { 417 | key: 'whitespace', 418 | value: function whitespace() { 419 | return this.add('\\s'); 420 | } 421 | 422 | // Modifiers // 423 | 424 | /** 425 | * Add a regex modifier/flag 426 | * @param {string} modifier modifier to add 427 | * @returns {VerbalExpression} recompiled instance of VerbalExpression 428 | * @memberof VerbalExpression 429 | */ 430 | 431 | }, { 432 | key: 'addModifier', 433 | value: function addModifier(modifier) { 434 | if (!this._modifiers.includes(modifier)) { 435 | this._modifiers += modifier; 436 | } 437 | 438 | return this.add(); 439 | } 440 | 441 | /** 442 | * Remove modifier 443 | * @param {string} modifier modifier to remove 444 | * @returns {VerbalExpression} recompiled instance of VerbalExpression 445 | * @memberof VerbalExpression 446 | */ 447 | 448 | }, { 449 | key: 'removeModifier', 450 | value: function removeModifier(modifier) { 451 | this._modifiers = this._modifiers.replace(modifier, ''); 452 | return this.add(); 453 | } 454 | 455 | /** 456 | * Control case-insensitive matching 457 | * @param {boolean} [enable=true] whether to enable this behaviour 458 | * @returns {VerbalExpression} recompiled instance of VerbalExpression 459 | * @memberof VerbalExpression 460 | */ 461 | 462 | }, { 463 | key: 'withAnyCase', 464 | value: function withAnyCase() { 465 | var enable = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true; 466 | 467 | return enable ? this.addModifier('i') : this.removeModifier('i'); 468 | } 469 | 470 | /** 471 | * Default behaviour is with "g" modifier, so we can turn this another way around than other modifiers 472 | * @param {boolean} [enable=true] whether to enable this behaviour 473 | * @returns {VerbalExpression} recompiled instance of VerbalExpression 474 | * @memberof VerbalExpression 475 | */ 476 | 477 | }, { 478 | key: 'stopAtFirst', 479 | value: function stopAtFirst() { 480 | var enable = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true; 481 | 482 | return enable ? this.removeModifier('g') : this.addModifier('g'); 483 | } 484 | 485 | /** 486 | * Control the multiline modifier 487 | * @param {boolean} [enable=true] whether to enable this behaviour 488 | * @returns {VerbalExpression} recompiled instance of VerbalExpression 489 | * @memberof VerbalExpression 490 | */ 491 | 492 | }, { 493 | key: 'searchOneLine', 494 | value: function searchOneLine() { 495 | var enable = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true; 496 | 497 | return enable ? this.removeModifier('m') : this.addModifier('m'); 498 | } 499 | 500 | // Loops // 501 | 502 | /** 503 | * Repeat the previous item exactly n times or between n and m times 504 | * @returns {VerbalExpression} recompiled instance of VerbalExpression 505 | * @memberof VerbalExpression 506 | */ 507 | 508 | }, { 509 | key: 'repeatPrevious', 510 | value: function repeatPrevious() { 511 | var isInteger = /\d+/; 512 | 513 | for (var _len = arguments.length, quantity = Array(_len), _key = 0; _key < _len; _key++) { 514 | quantity[_key] = arguments[_key]; 515 | } 516 | 517 | var values = quantity.filter(function (argument) { 518 | return isInteger.test(argument); 519 | }); 520 | 521 | if (values.length === 0 || values.length > 2) { 522 | return this; 523 | } 524 | 525 | this.add('{' + values.join(',') + '}'); 526 | 527 | return this; 528 | } 529 | 530 | /** 531 | * Repeat the previous at least once 532 | * @returns {VerbalExpression} recompiled instance of VerbalExpression 533 | * @memberof VerbalExpression 534 | */ 535 | 536 | }, { 537 | key: 'oneOrMore', 538 | value: function oneOrMore() { 539 | return this.add('+'); 540 | } 541 | 542 | /** 543 | * Match the value zero or more times 544 | * @param {string} value value to find 545 | * @param {integer} [lower] minimum number of times the value should be repeated 546 | * @param {integer} [upper] maximum number of times the value should be repeated 547 | * @returns {VerbalExpression} recompiled instance of VerbalExpression 548 | * @memberof VerbalExpression 549 | */ 550 | 551 | }, { 552 | key: 'multiple', 553 | value: function multiple(value, lower, upper) { 554 | if (value !== undefined) { 555 | value = VerbalExpression.sanitize(value); 556 | this.add('(?:' + value + ')'); 557 | } 558 | 559 | if (lower === undefined && upper === undefined) { 560 | this.add('*'); // Any number of times 561 | } else if (lower !== undefined && upper === undefined) { 562 | this.add('{' + lower + ',}'); 563 | } else if (lower !== undefined && upper !== undefined) { 564 | this.add('{' + lower + ',' + upper + '}'); 565 | } 566 | 567 | return this; 568 | } 569 | 570 | // Capture groups // 571 | 572 | /** 573 | * Starts a capturing group 574 | * @returns {VerbalExpression} recompiled instance of VerbalExpression 575 | * @memberof VerbalExpression 576 | */ 577 | 578 | }, { 579 | key: 'beginCapture', 580 | value: function beginCapture() { 581 | // Add the end of the capture group to the suffixes temporarily so that compilation continues to work 582 | this._suffixes += ')'; 583 | return this.add('('); 584 | } 585 | 586 | /** 587 | * Ends a capturing group 588 | * @returns {VerbalExpression} recompiled instance of VerbalExpression 589 | * @memberof VerbalExpression 590 | */ 591 | 592 | }, { 593 | key: 'endCapture', 594 | value: function endCapture() { 595 | // Remove the last parenthesis from the _suffixes and add it to the regex 596 | this._suffixes = this._suffixes.slice(0, -1); 597 | return this.add(')'); 598 | } 599 | 600 | // Miscellaneous // 601 | 602 | /** 603 | * Shorthand function for the string.replace function to allow for a more logical flow 604 | * @param {string} source string to search for 605 | * @param {string} value value to replace with 606 | * @returns {VerbalExpression} recompiled instance of VerbalExpression 607 | * @memberof VerbalExpression 608 | */ 609 | 610 | }, { 611 | key: 'replace', 612 | value: function replace(source, value) { 613 | source = source.toString(); 614 | return source.replace(this, value); 615 | } 616 | 617 | /** 618 | * Convert to RegExp object 619 | * @returns {RegExp} equivalent RegExp instance 620 | * @memberof VerbalExpression 621 | */ 622 | 623 | }, { 624 | key: 'toRegExp', 625 | value: function toRegExp() { 626 | var components = this.toString().match(/\/(.*)\/([gimuy]+)?/); 627 | var pattern = components[1]; 628 | var flags = components[2]; 629 | 630 | return new RegExp(pattern, flags); 631 | } 632 | }], [{ 633 | key: 'sanitize', 634 | value: function sanitize(value) { 635 | if (value instanceof RegExp) { 636 | return value.source; 637 | } 638 | 639 | if (typeof value === 'number') { 640 | return value; 641 | } 642 | 643 | if (typeof value !== 'string') { 644 | return ''; 645 | } 646 | 647 | // Regular expression to match meta characters 648 | // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/regexp 649 | var toEscape = /([\].|*?+(){}^$\\:=[])/g; 650 | 651 | // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/lastMatch 652 | var lastMatch = '$&'; 653 | 654 | // Escape meta characters 655 | return value.replace(toEscape, '\\' + lastMatch); 656 | } 657 | }]); 658 | 659 | return VerbalExpression; 660 | }(_extendableBuiltin(RegExp)); 661 | 662 | /** 663 | * Return a new instance of `VerbalExpression` 664 | * @export 665 | * @returns {VerbalExpression} new instance 666 | */ 667 | 668 | 669 | function VerEx() { 670 | // eslint-disable-line no-unused-vars 671 | var instance = new VerbalExpression(); 672 | instance.sanitize = VerbalExpression.sanitize; 673 | return instance; 674 | } 675 | //# sourceMappingURL=verbalexpressions.js.map 676 | 677 | return VerEx; 678 | 679 | })); 680 | -------------------------------------------------------------------------------- /dist/verbalexpressions.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["../VerbalExpressions.js"],"names":["VerbalExpression","_prefixes","_source","_suffixes","_modifiers","value","pattern","compile","enable","add","sanitize","then","Array","isArray","join","anyOf","i","length","from","to","lineBreak","modifier","includes","replace","addModifier","removeModifier","isInteger","quantity","values","filter","test","argument","lower","upper","undefined","slice","source","toString","components","match","flags","RegExp","toEscape","lastMatch","VerEx","instance"],"mappings":"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","file":"verbalexpressions.js","sourcesContent":["/**\r\n * @file VerbalExpressions JavaScript Library\r\n * @version 0.3.0\r\n * @license MIT\r\n *\r\n * @see https://github.com/VerbalExpressions/JSVerbalExpressions\r\n */\r\n\r\n/**\r\n * Define the VerbalExpression class\r\n *\r\n * @class VerbalExpression\r\n * @extends {RegExp}\r\n */\r\nclass VerbalExpression extends RegExp {\r\n /**\r\n * Creates an instance of VerbalExpression.\r\n * @constructor\r\n * @alias VerEx\r\n * @memberof VerbalExpression\r\n */\r\n constructor() {\r\n // Call the `RegExp` constructor so that `this` can be used\r\n super('', 'gm');\r\n\r\n // Variables to hold the expression construction in order\r\n this._prefixes = '';\r\n this._source = '';\r\n this._suffixes = '';\r\n this._modifiers = 'gm'; // 'global, multiline' matching by default\r\n }\r\n\r\n // Utility //\r\n\r\n /**\r\n * Escape meta-characters in the parameter and make it safe for adding to the expression\r\n * @static\r\n * @param {(string|RegExp|number)} value object to sanitize\r\n * @returns {string} sanitized value\r\n * @memberof VerbalExpression\r\n */\r\n static sanitize(value) {\r\n if (value instanceof RegExp) {\r\n return value.source;\r\n }\r\n\r\n if (typeof value === 'number') {\r\n return value;\r\n }\r\n\r\n if (typeof value !== 'string') {\r\n return '';\r\n }\r\n\r\n // Regular expression to match meta characters\r\n // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/regexp\r\n const toEscape = /([\\].|*?+(){}^$\\\\:=[])/g;\r\n\r\n // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/lastMatch\r\n const lastMatch = '$&';\r\n\r\n // Escape meta characters\r\n return value.replace(toEscape, `\\\\${lastMatch}`);\r\n }\r\n\r\n /**\r\n * Add stuff to the expression and compile the new expression so it's ready to be used.\r\n * @param {(string|number)} [value=''] stuff to add\r\n * @returns {VerbalExpression} recompiled instance of VerbalExpression\r\n * @memberof VerbalExpression\r\n */\r\n add(value = '') {\r\n this._source += value;\r\n const pattern = this._prefixes + this._source + this._suffixes;\r\n\r\n this.compile(pattern, this._modifiers);\r\n\r\n return this;\r\n }\r\n\r\n // Rules //\r\n\r\n /**\r\n * Control start-of-line matching\r\n * @param {boolean} [enable=true] whether to enable this behaviour\r\n * @returns {VerbalExpression} recompiled instance of VerbalExpression\r\n * @memberof VerbalExpression\r\n */\r\n startOfLine(enable = true) {\r\n this._prefixes = enable ? '^' : '';\r\n return this.add();\r\n }\r\n\r\n /**\r\n * Control end-of-line matching\r\n * @param {boolean} [enable=true] whether to enable this behaviour\r\n * @returns {VerbalExpression} recompiled instance of VerbalExpression\r\n * @memberof VerbalExpression\r\n */\r\n endOfLine(enable = true) {\r\n this._suffixes = enable ? '$' : '';\r\n return this.add();\r\n }\r\n\r\n /**\r\n * Look for the value passed\r\n * @param {(string|RegExp|number)} value value to find\r\n * @returns {VerbalExpression} recompiled instance of VerbalExpression\r\n * @memberof VerbalExpression\r\n */\r\n then(value) {\r\n value = VerbalExpression.sanitize(value);\r\n return this.add(`(?:${value})`);\r\n }\r\n\r\n /**\r\n * Alias for then() to allow for readable syntax when then() is the first method in the chain.\r\n * @param {(string|RegExp|numer)} value value to find\r\n * @returns {VerbalExpression} recompiled instance of VerbalExpression\r\n * @memberof VerbalExpression\r\n */\r\n find(value) {\r\n return this.then(value);\r\n }\r\n\r\n /**\r\n * Add optional values\r\n * @param {(string|RegExp|number)} value value to find\r\n * @returns {VerbalExpression} recompiled instance of VerbalExpression\r\n * @memberof VerbalExpression\r\n */\r\n maybe(value) {\r\n value = VerbalExpression.sanitize(value);\r\n return this.add(`(?:${value})?`);\r\n }\r\n\r\n /**\r\n * Add alternative expressions\r\n * @param {(string|RegExp|number)} value value to find\r\n * @returns {VerbalExpression} recompiled instance of VerbalExpression\r\n * @memberof VerbalExpression\r\n */\r\n or(value) {\r\n this._prefixes += '(?:';\r\n this._suffixes = `)${this._suffixes}`;\r\n\r\n this.add(')|(?:');\r\n\r\n if (value) {\r\n this.then(value);\r\n }\r\n\r\n return this;\r\n }\r\n\r\n /**\r\n * Any character any number of times\r\n * @returns {VerbalExpression} recompiled instance of VerbalExpression\r\n * @memberof VerbalExpression\r\n */\r\n anything() {\r\n return this.add('(?:.*)');\r\n }\r\n\r\n /**\r\n * Anything but these characters\r\n * @param {(string|number|string[]|number[])} value characters to not match\r\n * @returns {VerbalExpression} recompiled instance of VerbalExpression\r\n * @memberof VerbalExpression\r\n */\r\n anythingBut(value) {\r\n if (Array.isArray(value)) {\r\n value = value.join('');\r\n }\r\n\r\n value = VerbalExpression.sanitize(value);\r\n return this.add(`(?:[^${value}]*)`);\r\n }\r\n\r\n /**\r\n * Any character(s) at least once\r\n * @returns {VerbalExpression} recompiled instance of VerbalExpression\r\n * @memberof VerbalExpression\r\n */\r\n something() {\r\n return this.add('(?:.+)');\r\n }\r\n\r\n /**\r\n * Any character at least one time except for these characters\r\n * @param {(string|number|string[]|number[])} value characters to not match\r\n * @returns {VerbalExpression} recompiled instance of VerbalExpression\r\n * @memberof VerbalExpression\r\n */\r\n somethingBut(value) {\r\n if (Array.isArray(value)) {\r\n value = value.join('');\r\n }\r\n\r\n value = VerbalExpression.sanitize(value);\r\n return this.add(`(?:[^${value}]+)`);\r\n }\r\n\r\n /**\r\n * Match any of the given characters\r\n * @param {(string|number|string[]|number[])} value characters to match\r\n * @returns {VerbalExpression} recompiled instance of VerbalExpression\r\n * @memberof VerbalExpression\r\n */\r\n anyOf(value) {\r\n if (Array.isArray(value)) {\r\n value = value.join('');\r\n }\r\n\r\n value = VerbalExpression.sanitize(value);\r\n return this.add(`[${value}]`);\r\n }\r\n\r\n /**\r\n * Shorthand for anyOf(value)\r\n * @param {string|number} value value to find\r\n * @returns {VerbalExpression} recompiled instance of VerbalExpression\r\n * @memberof VerbalExpression\r\n */\r\n any(value) {\r\n return this.anyOf(value);\r\n }\r\n\r\n /**\r\n * Ensure that the parameter does not follow\r\n * @param {string|number} value\r\n * @returns {VerbalExpression} recompiled instance of VerbalExpression\r\n * @memberof VerbalExpression\r\n */\r\n not(value) {\r\n value = VerbalExpression.sanitize(value);\r\n this.add(`(?!${value})`);\r\n\r\n return this;\r\n }\r\n\r\n /**\r\n * Matching any character within a range of characters\r\n * Usage: .range( from, to [, from, to ... ] )\r\n * @param {...string} ranges characters denoting beginning and ending of ranges\r\n * @returns {VerbalExpression} recompiled instance of VerbalExpression\r\n * @memberof VerbalExpression\r\n */\r\n range(...ranges) {\r\n let value = '';\r\n\r\n for (let i = 1; i < ranges.length; i += 2) {\r\n const from = VerbalExpression.sanitize(ranges[i - 1]);\r\n const to = VerbalExpression.sanitize(ranges[i]);\r\n\r\n value += `${from}-${to}`;\r\n }\r\n\r\n return this.add(`[${value}]`);\r\n }\r\n\r\n // Special characters //\r\n\r\n /**\r\n * Match a Line break\r\n * @returns {VerbalExpression} recompiled instance of VerbalExpression\r\n * @memberof VerbalExpression\r\n */\r\n lineBreak() {\r\n return this.add('(?:\\\\r\\\\n|\\\\r|\\\\n)'); // Unix(LF) + Windows(CRLF)\r\n }\r\n\r\n /**\r\n * A shorthand for lineBreak() for html-minded users\r\n * @returns {VerbalExpression} recompiled instance of VerbalExpression\r\n * @memberof VerbalExpression\r\n */\r\n br() {\r\n return this.lineBreak();\r\n }\r\n\r\n /**\r\n * Match a tab character\r\n * @returns {VerbalExpression} recompiled instance of VerbalExpression\r\n * @memberof VerbalExpression\r\n */\r\n tab() {\r\n return this.add('\\\\t');\r\n }\r\n\r\n /**\r\n * Match any alphanumeric\r\n * @returns {VerbalExpression} recompiled instance of VerbalExpression\r\n * @memberof VerbalExpression\r\n */\r\n word() {\r\n return this.add('\\\\w+');\r\n }\r\n\r\n /**\r\n * Match a single digit\r\n * @returns {VerbalExpression} recompiled instance of VerbalExpression\r\n * @memberof VerbalExpression\r\n */\r\n digit() {\r\n return this.add('\\\\d');\r\n }\r\n\r\n /**\r\n * Match a single whitespace\r\n * @returns {VerbalExpression} recompiled instance of VerbalExpression\r\n * @memberof VerbalExpression\r\n */\r\n whitespace() {\r\n return this.add('\\\\s');\r\n }\r\n\r\n // Modifiers //\r\n\r\n /**\r\n * Add a regex modifier/flag\r\n * @param {string} modifier modifier to add\r\n * @returns {VerbalExpression} recompiled instance of VerbalExpression\r\n * @memberof VerbalExpression\r\n */\r\n addModifier(modifier) {\r\n if (!this._modifiers.includes(modifier)) {\r\n this._modifiers += modifier;\r\n }\r\n\r\n return this.add();\r\n }\r\n\r\n /**\r\n * Remove modifier\r\n * @param {string} modifier modifier to remove\r\n * @returns {VerbalExpression} recompiled instance of VerbalExpression\r\n * @memberof VerbalExpression\r\n */\r\n removeModifier(modifier) {\r\n this._modifiers = this._modifiers.replace(modifier, '');\r\n return this.add();\r\n }\r\n\r\n /**\r\n * Control case-insensitive matching\r\n * @param {boolean} [enable=true] whether to enable this behaviour\r\n * @returns {VerbalExpression} recompiled instance of VerbalExpression\r\n * @memberof VerbalExpression\r\n */\r\n withAnyCase(enable = true) {\r\n return enable ? this.addModifier('i') : this.removeModifier('i');\r\n }\r\n\r\n /**\r\n * Default behaviour is with \"g\" modifier, so we can turn this another way around than other modifiers\r\n * @param {boolean} [enable=true] whether to enable this behaviour\r\n * @returns {VerbalExpression} recompiled instance of VerbalExpression\r\n * @memberof VerbalExpression\r\n */\r\n stopAtFirst(enable = true) {\r\n return enable ? this.removeModifier('g') : this.addModifier('g');\r\n }\r\n\r\n /**\r\n * Control the multiline modifier\r\n * @param {boolean} [enable=true] whether to enable this behaviour\r\n * @returns {VerbalExpression} recompiled instance of VerbalExpression\r\n * @memberof VerbalExpression\r\n */\r\n searchOneLine(enable = true) {\r\n return enable ? this.removeModifier('m') : this.addModifier('m');\r\n }\r\n\r\n // Loops //\r\n\r\n /**\r\n * Repeat the previous item exactly n times or between n and m times\r\n * @returns {VerbalExpression} recompiled instance of VerbalExpression\r\n * @memberof VerbalExpression\r\n */\r\n repeatPrevious(...quantity) {\r\n const isInteger = /\\d+/;\r\n const values = quantity.filter(argument => isInteger.test(argument));\r\n\r\n if (values.length === 0 || values.length > 2) {\r\n return this;\r\n }\r\n\r\n this.add(`{${values.join(',')}}`);\r\n\r\n return this;\r\n }\r\n\r\n /**\r\n * Repeat the previous at least once\r\n * @returns {VerbalExpression} recompiled instance of VerbalExpression\r\n * @memberof VerbalExpression\r\n */\r\n oneOrMore() {\r\n return this.add('+');\r\n }\r\n\r\n /**\r\n * Match the value zero or more times\r\n * @param {string} value value to find\r\n * @param {integer} [lower] minimum number of times the value should be repeated\r\n * @param {integer} [upper] maximum number of times the value should be repeated\r\n * @returns {VerbalExpression} recompiled instance of VerbalExpression\r\n * @memberof VerbalExpression\r\n */\r\n multiple(value, lower, upper) {\r\n if (value !== undefined) {\r\n value = VerbalExpression.sanitize(value);\r\n this.add(`(?:${value})`);\r\n }\r\n\r\n if (lower === undefined && upper === undefined) {\r\n this.add('*'); // Any number of times\r\n } else if (lower !== undefined && upper === undefined) {\r\n this.add(`{${lower},}`);\r\n } else if (lower !== undefined && upper !== undefined) {\r\n this.add(`{${lower},${upper}}`);\r\n }\r\n\r\n return this;\r\n }\r\n\r\n // Capture groups //\r\n\r\n /**\r\n * Starts a capturing group\r\n * @returns {VerbalExpression} recompiled instance of VerbalExpression\r\n * @memberof VerbalExpression\r\n */\r\n beginCapture() {\r\n // Add the end of the capture group to the suffixes temporarily so that compilation continues to work\r\n this._suffixes += ')';\r\n return this.add('(');\r\n }\r\n\r\n /**\r\n * Ends a capturing group\r\n * @returns {VerbalExpression} recompiled instance of VerbalExpression\r\n * @memberof VerbalExpression\r\n */\r\n endCapture() {\r\n // Remove the last parenthesis from the _suffixes and add it to the regex\r\n this._suffixes = this._suffixes.slice(0, -1);\r\n return this.add(')');\r\n }\r\n\r\n // Miscellaneous //\r\n\r\n /**\r\n * Shorthand function for the string.replace function to allow for a more logical flow\r\n * @param {string} source string to search for\r\n * @param {string} value value to replace with\r\n * @returns {VerbalExpression} recompiled instance of VerbalExpression\r\n * @memberof VerbalExpression\r\n */\r\n replace(source, value) {\r\n source = source.toString();\r\n return source.replace(this, value);\r\n }\r\n\r\n /**\r\n * Convert to RegExp object\r\n * @returns {RegExp} equivalent RegExp instance\r\n * @memberof VerbalExpression\r\n */\r\n toRegExp() {\r\n const components = this.toString().match(/\\/(.*)\\/([gimuy]+)?/);\r\n const pattern = components[1];\r\n const flags = components[2];\r\n\r\n return new RegExp(pattern, flags);\r\n }\r\n}\r\n\r\n/**\r\n * Return a new instance of `VerbalExpression`\r\n * @export\r\n * @returns {VerbalExpression} new instance\r\n */\r\nfunction VerEx() { // eslint-disable-line no-unused-vars\r\n const instance = new VerbalExpression();\r\n instance.sanitize = VerbalExpression.sanitize;\r\n return instance;\r\n}\r\n"]} -------------------------------------------------------------------------------- /dist/verbalexpressions.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * verbal-expressions JavaScript Library v1.0.1 3 | * https://github.com/VerbalExpressions/JSVerbalExpressions 4 | * 5 | * Released under the MIT license 6 | */ 7 | 8 | !function(e,t){void 0===e&&void 0!==window&&(e=window),"function"==typeof define&&define.amd?define("VerEx",[],function(){return e.VerEx=t()}):"object"==typeof module&&module.exports?module.exports=t():e.VerEx=t()}(this,function(){var e=function(e,t,i){return t&&n(e.prototype,t),i&&n(e,i),e};function n(e,t){for(var i=0;i 1.0, >= 1.0.2) 8 | connection_pool (>= 2.2.5) 9 | drb 10 | i18n (>= 1.6, < 2) 11 | minitest (>= 5.1) 12 | mutex_m 13 | tzinfo (~> 2.0) 14 | addressable (2.8.6) 15 | public_suffix (>= 2.0.2, < 6.0) 16 | base64 (0.2.0) 17 | bigdecimal (3.1.6) 18 | coffee-script (2.4.1) 19 | coffee-script-source 20 | execjs 21 | coffee-script-source (1.12.2) 22 | colorator (1.1.0) 23 | commonmarker (0.23.10) 24 | concurrent-ruby (1.2.3) 25 | connection_pool (2.4.1) 26 | dnsruby (1.70.0) 27 | simpleidn (~> 0.2.1) 28 | drb (2.2.0) 29 | ruby2_keywords 30 | em-websocket (0.5.3) 31 | eventmachine (>= 0.12.9) 32 | http_parser.rb (~> 0) 33 | ethon (0.16.0) 34 | ffi (>= 1.15.0) 35 | eventmachine (1.2.7) 36 | eventmachine (1.2.7-x64-mingw32) 37 | execjs (2.9.1) 38 | faraday (2.9.0) 39 | faraday-net_http (>= 2.0, < 3.2) 40 | faraday-net_http (3.1.0) 41 | net-http 42 | ffi (1.16.3) 43 | ffi (1.16.3-x64-mingw32) 44 | forwardable-extended (2.6.0) 45 | gemoji (4.1.0) 46 | github-pages (231) 47 | github-pages-health-check (= 1.18.2) 48 | jekyll (= 3.9.5) 49 | jekyll-avatar (= 0.8.0) 50 | jekyll-coffeescript (= 1.2.2) 51 | jekyll-commonmark-ghpages (= 0.4.0) 52 | jekyll-default-layout (= 0.1.5) 53 | jekyll-feed (= 0.17.0) 54 | jekyll-gist (= 1.5.0) 55 | jekyll-github-metadata (= 2.16.1) 56 | jekyll-include-cache (= 0.2.1) 57 | jekyll-mentions (= 1.6.0) 58 | jekyll-optional-front-matter (= 0.3.2) 59 | jekyll-paginate (= 1.1.0) 60 | jekyll-readme-index (= 0.3.0) 61 | jekyll-redirect-from (= 0.16.0) 62 | jekyll-relative-links (= 0.6.1) 63 | jekyll-remote-theme (= 0.4.3) 64 | jekyll-sass-converter (= 1.5.2) 65 | jekyll-seo-tag (= 2.8.0) 66 | jekyll-sitemap (= 1.4.0) 67 | jekyll-swiss (= 1.0.0) 68 | jekyll-theme-architect (= 0.2.0) 69 | jekyll-theme-cayman (= 0.2.0) 70 | jekyll-theme-dinky (= 0.2.0) 71 | jekyll-theme-hacker (= 0.2.0) 72 | jekyll-theme-leap-day (= 0.2.0) 73 | jekyll-theme-merlot (= 0.2.0) 74 | jekyll-theme-midnight (= 0.2.0) 75 | jekyll-theme-minimal (= 0.2.0) 76 | jekyll-theme-modernist (= 0.2.0) 77 | jekyll-theme-primer (= 0.6.0) 78 | jekyll-theme-slate (= 0.2.0) 79 | jekyll-theme-tactile (= 0.2.0) 80 | jekyll-theme-time-machine (= 0.2.0) 81 | jekyll-titles-from-headings (= 0.5.3) 82 | jemoji (= 0.13.0) 83 | kramdown (= 2.4.0) 84 | kramdown-parser-gfm (= 1.1.0) 85 | liquid (= 4.0.4) 86 | mercenary (~> 0.3) 87 | minima (= 2.5.1) 88 | nokogiri (>= 1.13.6, < 2.0) 89 | rouge (= 3.30.0) 90 | terminal-table (~> 1.4) 91 | github-pages-health-check (1.18.2) 92 | addressable (~> 2.3) 93 | dnsruby (~> 1.60) 94 | octokit (>= 4, < 8) 95 | public_suffix (>= 3.0, < 6.0) 96 | typhoeus (~> 1.3) 97 | html-pipeline (2.14.3) 98 | activesupport (>= 2) 99 | nokogiri (>= 1.4) 100 | http_parser.rb (0.8.0) 101 | i18n (1.14.1) 102 | concurrent-ruby (~> 1.0) 103 | jekyll (3.9.5) 104 | addressable (~> 2.4) 105 | colorator (~> 1.0) 106 | em-websocket (~> 0.5) 107 | i18n (>= 0.7, < 2) 108 | jekyll-sass-converter (~> 1.0) 109 | jekyll-watch (~> 2.0) 110 | kramdown (>= 1.17, < 3) 111 | liquid (~> 4.0) 112 | mercenary (~> 0.3.3) 113 | pathutil (~> 0.9) 114 | rouge (>= 1.7, < 4) 115 | safe_yaml (~> 1.0) 116 | jekyll-avatar (0.8.0) 117 | jekyll (>= 3.0, < 5.0) 118 | jekyll-coffeescript (1.2.2) 119 | coffee-script (~> 2.2) 120 | coffee-script-source (~> 1.12) 121 | jekyll-commonmark (1.4.0) 122 | commonmarker (~> 0.22) 123 | jekyll-commonmark-ghpages (0.4.0) 124 | commonmarker (~> 0.23.7) 125 | jekyll (~> 3.9.0) 126 | jekyll-commonmark (~> 1.4.0) 127 | rouge (>= 2.0, < 5.0) 128 | jekyll-default-layout (0.1.5) 129 | jekyll (>= 3.0, < 5.0) 130 | jekyll-feed (0.17.0) 131 | jekyll (>= 3.7, < 5.0) 132 | jekyll-gist (1.5.0) 133 | octokit (~> 4.2) 134 | jekyll-github-metadata (2.16.1) 135 | jekyll (>= 3.4, < 5.0) 136 | octokit (>= 4, < 7, != 4.4.0) 137 | jekyll-include-cache (0.2.1) 138 | jekyll (>= 3.7, < 5.0) 139 | jekyll-mentions (1.6.0) 140 | html-pipeline (~> 2.3) 141 | jekyll (>= 3.7, < 5.0) 142 | jekyll-optional-front-matter (0.3.2) 143 | jekyll (>= 3.0, < 5.0) 144 | jekyll-paginate (1.1.0) 145 | jekyll-readme-index (0.3.0) 146 | jekyll (>= 3.0, < 5.0) 147 | jekyll-redirect-from (0.16.0) 148 | jekyll (>= 3.3, < 5.0) 149 | jekyll-relative-links (0.6.1) 150 | jekyll (>= 3.3, < 5.0) 151 | jekyll-remote-theme (0.4.3) 152 | addressable (~> 2.0) 153 | jekyll (>= 3.5, < 5.0) 154 | jekyll-sass-converter (>= 1.0, <= 3.0.0, != 2.0.0) 155 | rubyzip (>= 1.3.0, < 3.0) 156 | jekyll-sass-converter (1.5.2) 157 | sass (~> 3.4) 158 | jekyll-seo-tag (2.8.0) 159 | jekyll (>= 3.8, < 5.0) 160 | jekyll-sitemap (1.4.0) 161 | jekyll (>= 3.7, < 5.0) 162 | jekyll-swiss (1.0.0) 163 | jekyll-theme-architect (0.2.0) 164 | jekyll (> 3.5, < 5.0) 165 | jekyll-seo-tag (~> 2.0) 166 | jekyll-theme-cayman (0.2.0) 167 | jekyll (> 3.5, < 5.0) 168 | jekyll-seo-tag (~> 2.0) 169 | jekyll-theme-dinky (0.2.0) 170 | jekyll (> 3.5, < 5.0) 171 | jekyll-seo-tag (~> 2.0) 172 | jekyll-theme-hacker (0.2.0) 173 | jekyll (> 3.5, < 5.0) 174 | jekyll-seo-tag (~> 2.0) 175 | jekyll-theme-leap-day (0.2.0) 176 | jekyll (> 3.5, < 5.0) 177 | jekyll-seo-tag (~> 2.0) 178 | jekyll-theme-merlot (0.2.0) 179 | jekyll (> 3.5, < 5.0) 180 | jekyll-seo-tag (~> 2.0) 181 | jekyll-theme-midnight (0.2.0) 182 | jekyll (> 3.5, < 5.0) 183 | jekyll-seo-tag (~> 2.0) 184 | jekyll-theme-minimal (0.2.0) 185 | jekyll (> 3.5, < 5.0) 186 | jekyll-seo-tag (~> 2.0) 187 | jekyll-theme-modernist (0.2.0) 188 | jekyll (> 3.5, < 5.0) 189 | jekyll-seo-tag (~> 2.0) 190 | jekyll-theme-primer (0.6.0) 191 | jekyll (> 3.5, < 5.0) 192 | jekyll-github-metadata (~> 2.9) 193 | jekyll-seo-tag (~> 2.0) 194 | jekyll-theme-slate (0.2.0) 195 | jekyll (> 3.5, < 5.0) 196 | jekyll-seo-tag (~> 2.0) 197 | jekyll-theme-tactile (0.2.0) 198 | jekyll (> 3.5, < 5.0) 199 | jekyll-seo-tag (~> 2.0) 200 | jekyll-theme-time-machine (0.2.0) 201 | jekyll (> 3.5, < 5.0) 202 | jekyll-seo-tag (~> 2.0) 203 | jekyll-titles-from-headings (0.5.3) 204 | jekyll (>= 3.3, < 5.0) 205 | jekyll-watch (2.2.1) 206 | listen (~> 3.0) 207 | jemoji (0.13.0) 208 | gemoji (>= 3, < 5) 209 | html-pipeline (~> 2.2) 210 | jekyll (>= 3.0, < 5.0) 211 | kramdown (2.4.0) 212 | rexml 213 | kramdown-parser-gfm (1.1.0) 214 | kramdown (~> 2.0) 215 | liquid (4.0.4) 216 | listen (3.8.0) 217 | rb-fsevent (~> 0.10, >= 0.10.3) 218 | rb-inotify (~> 0.9, >= 0.9.10) 219 | mercenary (0.3.6) 220 | mini_portile2 (2.8.6) 221 | minima (2.5.1) 222 | jekyll (>= 3.5, < 5.0) 223 | jekyll-feed (~> 0.9) 224 | jekyll-seo-tag (~> 2.1) 225 | minitest (5.22.2) 226 | mutex_m (0.2.0) 227 | net-http (0.4.1) 228 | uri 229 | nokogiri (1.16.5) 230 | mini_portile2 (~> 2.8.2) 231 | racc (~> 1.4) 232 | nokogiri (1.16.5-x64-mingw32) 233 | racc (~> 1.4) 234 | octokit (4.25.1) 235 | faraday (>= 1, < 3) 236 | sawyer (~> 0.9) 237 | pathutil (0.16.2) 238 | forwardable-extended (~> 2.6) 239 | public_suffix (5.0.4) 240 | racc (1.7.3) 241 | rb-fsevent (0.11.2) 242 | rb-inotify (0.10.1) 243 | ffi (~> 1.0) 244 | rexml (3.2.8) 245 | strscan (>= 3.0.9) 246 | rouge (3.30.0) 247 | ruby2_keywords (0.0.5) 248 | rubyzip (2.3.2) 249 | safe_yaml (1.0.5) 250 | sass (3.7.4) 251 | sass-listen (~> 4.0.0) 252 | sass-listen (4.0.0) 253 | rb-fsevent (~> 0.9, >= 0.9.4) 254 | rb-inotify (~> 0.9, >= 0.9.7) 255 | sawyer (0.9.2) 256 | addressable (>= 2.3.5) 257 | faraday (>= 0.17.3, < 3) 258 | simpleidn (0.2.1) 259 | unf (~> 0.1.4) 260 | strscan (3.1.0) 261 | terminal-table (1.8.0) 262 | unicode-display_width (~> 1.1, >= 1.1.1) 263 | typhoeus (1.4.1) 264 | ethon (>= 0.9.0) 265 | tzinfo (2.0.6) 266 | concurrent-ruby (~> 1.0) 267 | unf (0.1.4) 268 | unf_ext 269 | unf_ext (0.0.9.1) 270 | unf_ext (0.0.9.1-x64-mingw32) 271 | unicode-display_width (1.8.0) 272 | uri (0.13.0) 273 | 274 | PLATFORMS 275 | ruby 276 | x64-mingw32 277 | 278 | DEPENDENCIES 279 | github-pages 280 | 281 | BUNDLED WITH 282 | 1.17.2 283 | -------------------------------------------------------------------------------- /docs/VerEx.md: -------------------------------------------------------------------------------- 1 | # `VerEx` 2 | 3 | Return a new instance of [`VerbalExpression`](VerbalExpression). 4 | 5 | This is the function that is exported from within `VerbalExpressions.js` and is to be the first method in chains that describe verbal expressions. 6 | -------------------------------------------------------------------------------- /docs/VerbalExpression/capture-groups.md: -------------------------------------------------------------------------------- 1 | # Capture Groups 2 | 3 | Capture groups are used to extract data from within the regular expression match for further processing. 4 | 5 | ## `beginCapture` 6 | 7 | Begin a capture group. 8 | 9 | ## `endCapture` 10 | 11 | End a capture group. 12 | 13 | ___ 14 | 15 | ```js 16 | const phoneNumber = VerEx() 17 | .find('+') 18 | .beginCapture() 19 | .digit().repeatPrevious(2) 20 | .endCapture() 21 | .then('-') 22 | .digit().repeatPrevious(10); 23 | 24 | const [, countryCode] = phoneNumber.exec('+91-2223387510'); 25 | console.log(countryCode); // => '91' 26 | ``` 27 | -------------------------------------------------------------------------------- /docs/VerbalExpression/constructor.md: -------------------------------------------------------------------------------- 1 | # Constructor 2 | 3 | ## `constructor` 4 | 5 | Construct and return a new instance of [`VerbalExpression`](#verbalexpression). Used to support the `new VerbalExpression()` syntax in ES6 classes as mandated by [the spec](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/constructor). You usually wouldn't need to call `VerEx().constructor()`. 6 | -------------------------------------------------------------------------------- /docs/VerbalExpression/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: VerbalExpression 3 | --- 4 | 5 | # `VerbalExpression` 6 | 7 | A class that extends [`RegExp`](//developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp) and wraps all VerbalExpressions functionality. 8 | 9 | ## Table of Contents 10 | 11 | - [Constructor](../VerbalExpression/constructor) 12 | - [`constructor`](../VerbalExpression/constructor#constructor) 13 | - [Utilities](../VerbalExpression/utilities) 14 | - [`static sanitize`](../VerbalExpression/utilities#static) 15 | - [`add`](../VerbalExpression/utilities#add) 16 | - [Rules](../VerbalExpression/rules) 17 | - [`startOfLine`](../VerbalExpression/rules#startOfLine) 18 | - [`endOfLine`](../VerbalExpression/rules#endOfLine) 19 | - [`then`](../VerbalExpression/rules#then) 20 | - [`find`](../VerbalExpression/rules#find) 21 | - [`maybe`](../VerbalExpression/rules#maybe) 22 | - [`or`](../VerbalExpression/rules#or) 23 | - [`anything`](../VerbalExpression/rules#anything) 24 | - [`anythingBut`](../VerbalExpression/rules#anythingBut) 25 | - [`something`](../VerbalExpression/rules#something) 26 | - [`somethingBut`](../VerbalExpression/rules#somethingBut) 27 | - [`anyOf`](../VerbalExpression/rules#anyOf) 28 | - [`any`](../VerbalExpression/rules#any) 29 | - [`not`](../VerbalExpression/rules#not) 30 | - [`range`](../VerbalExpression/rules#range) 31 | - [Special Characters](../VerbalExpression/special-characters) 32 | - [`lineBreak`](../VerbalExpression/special-characters#lineBreak) 33 | - [`br`](../VerbalExpression/special-characters#br) 34 | - [`tab`](../VerbalExpression/special-characters#tab) 35 | - [`word`](../VerbalExpression/special-characters#word) 36 | - [`digit`](../VerbalExpression/special-characters#digit) 37 | - [`whitespace`](../VerbalExpression/special-characters#whitespace) 38 | - [Modifiers](../VerbalExpression/modifiers) 39 | - [`addModifier`](../VerbalExpression/modifiers#addModifier) 40 | - [`removeModifier`](../VerbalExpression/modifiers#removeModifier) 41 | - [`withAnyCase`](../VerbalExpression/modifiers#withAnyCase) 42 | - [`stopAtFirst`](../VerbalExpression/modifiers#stopAtFirst) 43 | - [`searchOneLine`](../VerbalExpression/modifiers#searchOneLine) 44 | - [`repeatPrevious`](../VerbalExpression/modifiers#repeatPrevious) 45 | - [Loops](../VerbalExpression/loops) 46 | - [`oneOrMore`](../VerbalExpression/loops#oneOrMore) 47 | - [`multiple`](../VerbalExpression/loops#multiple) 48 | - [Capture Groups](../VerbalExpression/capture-groups) 49 | - [`beginCapture`](../VerbalExpression/capture-groups#beginCapture) 50 | - [`endCapture`](../VerbalExpression/capture-groups#endCapture) 51 | - [Miscellaneous](../VerbalExpression/miscellaneous) 52 | - [`replace`](../VerbalExpression/miscellaneous#replace) 53 | - [`toRegExp`](../VerbalExpression/miscellaneous#toRegExp) 54 | -------------------------------------------------------------------------------- /docs/VerbalExpression/loops.md: -------------------------------------------------------------------------------- 1 | # Loops 2 | 3 | ## `oneOrMore` 4 | 5 | Match the previous stuff one or more times. 6 | 7 | ```js 8 | const integer = VerEx().digit().oneOrMore(); 9 | console.log(integer.exec('foo 12345')[0]); // => '12345' 10 | ``` 11 | 12 | ## `multiple` 13 | 14 | ### Usage 1 15 | 16 | Match the previous group any number of times. 17 | 18 | ```js 19 | const expr = VerEx().startOfLine().find(' ').multiple().endOfLine(); 20 | 21 | console.log(expr.test(' ')); // => true 22 | ``` 23 | 24 | ### Usage 2 25 | 26 | Match something zero or more times. 27 | 28 | Parameter | Expected type | Description 29 | ----------|---------------|-------------- 30 | `value` | `String` | Item to match 31 | 32 | ```js 33 | const expr = VerEx() 34 | .find('what').multiple('?') 35 | .endOfLine(); 36 | 37 | console.log(expr.test('what')); // => true 38 | expr.lastIndex = 0; 39 | console.log(expr.test('what???'));// => true 40 | ``` 41 | 42 | ### Usage 3 43 | 44 | Match something greater than or equal to `min` number of times. 45 | 46 | Parameter | Expected type | Description 47 | ----------|---------------|--------------------------------------------- 48 | `value` | `String` | Item to match 49 | `min` | `Number` | Minimum number of times it should be present 50 | 51 | ```js 52 | const expr = VerEx() 53 | .find('hurray').then('!').multiple(1) 54 | .endOfLine(); 55 | 56 | console.log(expr.test('hurray')); // => false 57 | expr.lastIndex = 0; 58 | console.log(expr.test('hurray!!')); // => true 59 | ``` 60 | 61 | ### Usage 4 62 | 63 | Match something between `min` and `max` (inclusive) number of times. 64 | 65 | Parameter | Expected type | Description 66 | ----------|---------------|--------------------------------------------- 67 | `value` | `String` | Item to match 68 | `min` | `Number` | Minimum number of times it should be present 69 | `max` | `Number` | Maximum number of times it should be present 70 | 71 | ```js 72 | const expr = VerEx() 73 | .find('h').then('i').multiple(1, 3) 74 | .endOfLine(); 75 | 76 | console.log(expr.test('hiii')); // => true 77 | expr.lastIndex = 0; 78 | console.log(expr.test('hiiii')); // => false 79 | ``` 80 | -------------------------------------------------------------------------------- /docs/VerbalExpression/miscellaneous.md: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | 3 | ## `replace` 4 | 5 | Replace characters matching the VerbalExpression in a string with another string. 6 | 7 | Parameter | Expected type | Description 8 | ----------|---------------|------------------------------- 9 | `source` | `String` | String to look for matches in 10 | `value` | `String` | String to replace matches with 11 | 12 | Return type: [`String`](//developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String) 13 | 14 | ```js 15 | const spaces = VerEx().find(' '); 16 | const fileName = 'a file name.txt'; 17 | 18 | // => 'a_file_name.txt' 19 | console.log(spaces.replace(fileName, '_')); 20 | ``` 21 | 22 | ## `toRegExp` 23 | 24 | Convert the class to a [`RegExp`](//developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp) object. 25 | 26 | Return type: [`RegExp`](//developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp) 27 | 28 | ```js 29 | const expr = VerEx().find('foo'); 30 | console.log(expr.toRegExp()); // => /(?:foo)/gm 31 | ``` 32 | -------------------------------------------------------------------------------- /docs/VerbalExpression/modifiers.md: -------------------------------------------------------------------------------- 1 | # Modifiers 2 | 3 | ## `addModifier` 4 | 5 | Manually add a regex modifier (flag). 6 | 7 | Parameter | Expected type | Description 8 | ----------|---------------|---------------- 9 | `value` | `String` | Modifier to add 10 | 11 | ```js 12 | let expr = VerEx() 13 | console.log(expr.flags); // => 'gm' 14 | 15 | expr = expr.addModifier('i'); 16 | console.log(expr.flags); // => 'gim' 17 | ``` 18 | 19 | ## `removeModifier` 20 | 21 | Manually remove a regex modifier (flag). 22 | 23 | Parameter | Expected type | Description 24 | ----------|---------------|------------------- 25 | `value` | `String` | Modifier to remove 26 | 27 | ```js 28 | let expr = VerEx(); 29 | console.log(expr.flags); // => 'gm' 30 | 31 | expr = expr.removeModifier('m'); 32 | console.log(expr.flags); // => 'g' 33 | ``` 34 | 35 | ## `withAnyCase` 36 | 37 | Control case-insensitive matching. Equivalent to adding or removing the `i` modifier. 38 | 39 | Parameter | Expected type | Description 40 | ----------|---------------|------------ 41 | `enable` (defaults to `true`) | `boolean` | Whether to enable this behavior 42 | 43 | ```js 44 | const hexColorCode = VerEx() 45 | .find('#') 46 | .range('0', '9', 'a', 'f') 47 | .repeatPrevious(6) 48 | .withAnyCase(); 49 | 50 | console.log(hexColorCode.test('#93afee')); // => true 51 | hexColorCode.lastIndex = 0; 52 | console.log(hexColorCode.test('#93AFEE')); // => true 53 | ``` 54 | 55 | ## `stopAtFirst` 56 | 57 | Control global matching. Enabling would cause the expression to not look for matches beyond the first match. Equivalent to removing or adding the `g` modifier. Global matching is enabled by default. 58 | 59 | Parameter | Expected type | Description 60 | ----------|---------------|------------ 61 | `enable` (defaults to `true`) | `boolean` | Whether to enable this behavior 62 | 63 | ```js 64 | ``` 65 | 66 | ## `searchOneLine` 67 | 68 | Control multi-line matching. Enabling would cause the expression to not look for matches beyond the first line. Equivalent to removing or adding the `m` modifier. Multi-line matching is enabled by default. 69 | 70 | Parameter | Expected type | Description 71 | ----------|---------------|------------ 72 | `enable` (defaults to `true`) | `boolean` | Whether to enable this behavior 73 | 74 | ```js 75 | let findFoo = VerEx().startOfLine().find('foo').endOfLine(); 76 | console.log(findFoo.test('foo\nfoo\nfoo')); // => true 77 | 78 | findFoo = findFoo.searchOneLine(); 79 | console.log(findFoo.test('foo\nfoo\nfoo')); // => false 80 | ``` 81 | 82 | ## `repeatPrevious` 83 | 84 | ### Usage 1 85 | 86 | Repeat the previous item exactly `count` times. 87 | 88 | Parameter | Expected type | Description 89 | ----------|---------------|------------ 90 | `count` | `Number` | Number of times to repeat the previous item 91 | 92 | ```js 93 | const expr = VerEx() 94 | .startOfLine() 95 | .find('foo') 96 | .repeatPrevious(2) 97 | .endOfLine(); 98 | 99 | console.log(expr.test('foofoo')); // => true 100 | expr.lastIndex = 0; 101 | console.log(expr.test('foofoofoo')); // => false 102 | ``` 103 | 104 | ### Usage 2 105 | 106 | Repeat the previous item between `mix` and `max` (inclusive) times. 107 | 108 | Parameter | Expected type | Description 109 | ----------|---------------|------------ 110 | `min` | `Number` | Minimum number of times to repeat the previous item 111 | `max` | `Number` | Maximum number of times to repeat the previous item 112 | 113 | ```js 114 | const expr = VerEx() 115 | .startOfLine() 116 | .find('foo') 117 | .repeatPrevious(1, 3) 118 | .endOfLine(); 119 | 120 | console.log(expr.test('foo')); // => true 121 | expr.lastIndex = 0; 122 | console.log(expr.test('foofoo')); // => true 123 | expr.lastIndex = 0; 124 | console.log(expr.test('foofoofoo')); // => true 125 | expr.lastIndex = 0; 126 | console.log(expr.test('foofoofoofoo')); // => false 127 | ``` 128 | -------------------------------------------------------------------------------- /docs/VerbalExpression/rules.md: -------------------------------------------------------------------------------- 1 | # Rules 2 | 3 | ## `startOfLine` 4 | 5 | Control whether to match the expression only if it appears from the beginning of the line. 6 | 7 | Parameter | Expected type | Description 8 | ----------|---------------|------------ 9 | `enable` (defaults to `true`) | `boolean` | Whether to enable this behavior 10 | 11 | ```js 12 | const expr1 = VerEx().find('apple'); 13 | console.log(expr1.test('pineapple')); // => true 14 | 15 | const expr2 = VerEx().startOfLine().find('apple'); 16 | console.log(expr2.test('pineapple')); // => false 17 | ``` 18 | 19 | ## `endOfLine` 20 | 21 | Control whether to match the expression only if it appears till the end of the line. 22 | 23 | Parameter | Expected type | Description 24 | ----------|---------------|------------ 25 | `enable` (defaults to `true`) | `boolean` | Whether to enable this behavior 26 | 27 | ```js 28 | const expr1 = VerEx().find('apple'); 29 | console.log(expr1.test('apples')); // => true 30 | 31 | const expr2 = VerEx().find('apple').endOfLine(); 32 | console.log(expr2.test('apples')); // => false 33 | ``` 34 | 35 | ## `then` 36 | 37 | Match an expression. 38 | 39 | Parameter | Expected type | Description 40 | ----------|---------------|------------ 41 | `value` | `String`, `number`, `RegExp`, `VerbalExpression` | Expression to match 42 | 43 | ```js 44 | const expr = VerEx().then('foo'); 45 | console.log(expr.test('foo')); // => true 46 | ``` 47 | 48 | ## `find` 49 | 50 | Alias for [`then`](#then). Meant for semantics when used at the beginning of a verbal expression. For example, `VerEx().find('foo')` is more readable than `VerEx().then('foo')`. 51 | 52 | ## `maybe` 53 | 54 | Optionally match an expression. 55 | 56 | Parameter | Expected type | Description 57 | ----------|---------------|------------ 58 | `value` | `String`, `number`, `RegExp`, `VerbalExpression` | Expression to optionally match 59 | 60 | ```js 61 | const protocol = VerEx().find('http').maybe('s').then('://'); 62 | 63 | console.log(protocol.test('http://')); // => true 64 | protocol.lastIndex = 0; 65 | console.log(protocol.test('https://')); // => true 66 | ``` 67 | 68 | ## `or` 69 | 70 | Alternatively, match another expression. 71 | 72 | Parameter | Expected type | Description 73 | ----------|---------------|------------ 74 | `value` (optional) | `String`, `number`, `RegExp`, `VerbalExpression` | Expression to match instead 75 | 76 | If no parameters are passed into `or`, the alternate expression would be the one built after the call to `or`. 77 | 78 | ```js 79 | let fooOrBar = VerEx().find('foo').or('bar'); 80 | console.log(expr.test('foo')); // => true 81 | fooOrBar.lastIndex = 0 82 | console.log(expr.test('bar')); // => true 83 | 84 | // alternate syntax 85 | fooOrBar = VerEx().find('foo').or().find('bar'); 86 | console.log(expr.test('foo')); // => true 87 | fooOrBar.lastIndex = 0 88 | console.log(expr.test('bar')); // => true 89 | ``` 90 | 91 | ## `anything` 92 | 93 | Match any character(s) any (including zero) number of times. 94 | 95 | ```js 96 | const anything = VerEx().anything(); 97 | 98 | console.log(anything.test('')); // => true 99 | anything.lastIndex = 0; 100 | console.log(anything.test('x')); // => true 101 | ``` 102 | 103 | ## `anythingBut` 104 | 105 | Match any character(s) except these any (including zero) number of times. 106 | 107 | Parameter | Expected type | Description 108 | ----------|----------------------|------------------------ 109 | `value` | `String`, `[String]` | Characters to not match 110 | 111 | ```js 112 | const anythingButXyz = VerEx().anythingBut('xyz'); 113 | 114 | console.log(anythingButXyz.test('')); // => true 115 | anythingButXyz.lastIndex = 0; 116 | console.log(anythingButXyz.test('a')); // => true 117 | anythingButXyz.lastIndex = 0; 118 | console.log(anythingButXyz.test('x')); // => false 119 | ``` 120 | 121 | ## `something` 122 | 123 | Match any character(s) at least once. 124 | 125 | ```js 126 | const something = VerEx().something(); 127 | 128 | console.log(something.test('abc')); // => true 129 | something.lastIndex = 0; 130 | console.log(something.test('')); // => false 131 | ``` 132 | 133 | ## `somethingBut` 134 | 135 | Match any character(s) except these at least once. 136 | 137 | Parameter | Expected type | Description 138 | ----------|----------------------|------------------------ 139 | `value` | `String`, `[String]` | Characters to not match 140 | 141 | ```js 142 | const somethingButXyz = VerEx().somethingBut('xyz'); 143 | 144 | console.log(somethingButXyz.test('abc')); // => true 145 | somethingButXyz.lastIndex = 0; 146 | console.log(somethingButXyz.test('')); // => false 147 | somethingButXyz.lastIndex = 0; 148 | console.log(somethingButXyz.test('xyz')); // => false 149 | ``` 150 | 151 | ## `anyOf` 152 | 153 | Match any of these characters exactly once. 154 | 155 | Parameter | Expected type | Description 156 | ----------|-----------------------|-------------------- 157 | `value` | `String`, `[String]` | Characters to match 158 | 159 | ```js 160 | const expr = VerEx().anyOf('abc'); 161 | console.log(expr.test('c')); // => true 162 | expr.lastIndex = 0; 163 | console.log(expr.test('d')); // => false 164 | ``` 165 | 166 | ## `any` 167 | 168 | Alias for [`anyOf`](#anyof). 169 | 170 | ## `not` 171 | 172 | Ensure that the parameter does not follow. 173 | 174 | Parameter | Expected type | Description 175 | ----------|-----------------|--------------------------- 176 | `value` | `String|Number` | Value to ensure absence of 177 | 178 | ```js 179 | const notLeapDay = VerEx().startOfLine()not('FEB-29').something().endOfLine(); 180 | 181 | console.log(notLeapDay.test('FEB-29-2017')); // => false 182 | notLeapDay.lastIndex = 0; 183 | console.log(notLeapDay.test('FEB-28-2017')); // => true 184 | ``` 185 | 186 | ## `range` 187 | 188 | Match any character within the range defined by the parameters. 189 | 190 | Parameter | Expected type | Description 191 | -----------|---------------|-------------------- 192 | `...range` | `String[]` | Range of characters 193 | 194 | Arguments will be interpreted as pairs. 195 | 196 | For example, `.range('a', 'z', '0', '9')` will be interpreted to mean any character within the ranges `a–z` (ascii x–y) or `0–9` (ascii x–y). The method expects an even number of parameters; unpaired parameters are ignored. 197 | 198 | ```js 199 | const hex = VerEx().range('0', '9', 'a', 'f').oneOrMore(); 200 | 201 | console.log(hex.test('b39a3f')); // => true 202 | hex.lastIndex = 0; 203 | console.log(hex.test('b39aeg')); // => false 204 | ``` 205 | -------------------------------------------------------------------------------- /docs/VerbalExpression/special-characters.md: -------------------------------------------------------------------------------- 1 | # Special Characters 2 | 3 | ## `lineBreak` 4 | 5 | Match a line break (both [Unix style](//codepoints.net/U+000A) and [Windows style](//codepoints.net/U+000D)). 6 | 7 | ```js 8 | const expr = VerEx().find('foo').lineBreak().then('bar'); 9 | console.log(expr.test('foo\nbar')); 10 | ``` 11 | 12 | ## `br` 13 | 14 | An alias for [`lineBreak`](#linebreak). 15 | 16 | ## `tab` 17 | 18 | Match a [tab character](//codepoints.net/U+0009). 19 | 20 | ```js 21 | const tabs = VerEx().tab(); 22 | const code = '\tconsole.log("tabs vs spaces")'; 23 | 24 | // => ' console.log("tabs vs spaces")' 25 | console.log(tabs.replace(code, ' ')); 26 | ``` 27 | 28 | ## `word` 29 | 30 | Match a word—a string of word characters (a–z, A–Z, 0–9 or \_). 31 | 32 | ```js 33 | const word = VerEx().startOfLine().word().endOfLine(); 34 | 35 | console.log(word.test('foo')); // => true 36 | word.lastIndex = 0; 37 | console.log(word.test('foo-bar')); // => false 38 | ``` 39 | 40 | ## `digit` 41 | 42 | Match a digit (0–9). 43 | 44 | ```js 45 | const digit = VerEx().digit(); 46 | console.log(digit.test('2')); // => true 47 | ``` 48 | 49 | ## `whitespace` 50 | 51 | Match a whitespace character (one of [space](//codepoints.net/U+0020), [tab](//codepoints.net/U+0009), [carriage return](//codepoints.net/U+000D), [new line](//codepoints.net/U+000), [vertical tab](//codepoints.net/U+000B) and [form feed](//codepoints.net/U+000C)). 52 | 53 | ```js 54 | const expr = VerEx().word().whitespace().word(); 55 | console.log(expr.test('word\tword')); // => true 56 | ``` 57 | -------------------------------------------------------------------------------- /docs/VerbalExpression/utilities.md: -------------------------------------------------------------------------------- 1 | # Utilities 2 | 3 | ## `static sanitize` 4 | 5 | Escape characters expected special by regex engines (all of `.`, `|`, `*`, `?`, `+`, `(`, `)`, `{`, `}`, `^`, `$`, `\`, `:`, `=`, `[` and `]`). 6 | 7 | Parameter | Expected type | Description 8 | ----------|---------------|------------------- 9 | `value` | `String` | String to sanitize 10 | 11 | This method will not be accessible from outside the source file since `VerEx()` returns an instance of the class rather than the class itself. 12 | 13 | ```js 14 | const stringToEscape = '(http://example.com?arg=foo+bar)'; 15 | 16 | // => '\(http:\/\/example.com\?arg\=foo\+bar\)' 17 | console.log(VerbalExpression.sanitize(stringToEscape)); 18 | ``` 19 | 20 | `sanitize` is a static method on the `VerbalExpression` class. However, it is also exposed as `VerEx().sanitize`. 21 | 22 | ## `add` 23 | 24 | Append a literal expression to the object. 25 | 26 | Parameter | Expected type | Description 27 | ----------------------------|---------------|-------------------------------- 28 | `value` (defaults to `''`) | `String` | Expression to add to the object 29 | 30 | ```js 31 | const expr = VerEx(); 32 | expr.add('(foo)?(?:bar)*'); 33 | 34 | console.log(expr); // => /(foo)?(?:bar)*/gm 35 | ``` 36 | -------------------------------------------------------------------------------- /docs/_config.yml: -------------------------------------------------------------------------------- 1 | title: JSVerbalExpressions Docs 2 | description: API Documentation for JSVerbalExpressions. 3 | repository: VerbalExpressions/JSVerbalExpressions 4 | 5 | show_downloads: true 6 | 7 | theme: jekyll-theme-minimal 8 | 9 | exclude: 10 | - Gemfile 11 | - Gemfile.lock 12 | - .gitignore 13 | 14 | cdn_url: https://jsdelivr.com/package/npm/verbal-expressions 15 | npm_url: https://npmjs.com/package/verbal-expressions 16 | minified_url: https://cdn.jsdelivr.net/npm/verbal-expressions@latest/dist/verbalexpressions.min.js 17 | 18 | -------------------------------------------------------------------------------- /docs/_layouts/default.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | {% seo %} 9 | 10 | 11 | 12 | 15 | 16 | 17 |
18 |
19 |

{{ site.title | default: site.github.repository_name }}

20 | 21 |

{{ site.description | default: site.github.project_tagline }}

22 | 23 | {% if site.logo %} 24 | Logo 25 | {% endif %} 26 | 27 | {% if site.github.is_project_page %} 28 |

View the Project on GitHub
{{ site.github.repository_nwo }}

29 | {% endif %} 30 | 31 | {% if site.github.is_user_page %} 32 |

View My GitHub Profile

33 | {% endif %} 34 | 35 |
36 | 37 | VerExVerbalExpression 38 | 39 |


40 | 41 | 46 |
47 | 48 |
{{ content }}
49 |
50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /docs/assets/css/style.scss: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | 4 | @import "{{ site.theme }}"; 5 | 6 | .wrapper { 7 | width: 900px; 8 | } 9 | 10 | section { 11 | width: 540px; 12 | } 13 | 14 | ul { 15 | margin-bottom: 5px; 16 | list-style: none; 17 | padding-left: 2em; 18 | } 19 | 20 | hr { 21 | margin: 20px 0; 22 | } 23 | 24 | a:hover { 25 | font-weight: inherit; 26 | } 27 | 28 | a code { 29 | color: #267CB9; 30 | } 31 | 32 | a code:hover { 33 | color: #006699; 34 | } 35 | 36 | details { 37 | padding-bottom: 20px; 38 | } 39 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Home 3 | --- 4 | 5 | VerbalExpressions is a JavaScript library that helps to construct difficult regular expressions. For more details, refer to the [README](//github.com/VerbalExpressions/JSVerbalExpressions#readme). 6 | 7 | # Table Of Contents 8 | 9 | - [`VerEx`](VerEx) 10 | - [`VerbalExpression`](VerbalExpression) 11 | - [Constructor](VerbalExpression/constructor) 12 | - [Utilities](VerbalExpression/utilities) 13 | - [Rules](VerbalExpression/rules) 14 | - [Special Characters](VerbalExpression/special-characters) 15 | - [Modifiers](VerbalExpression/modifiers) 16 | - [Loops](VerbalExpression/loops) 17 | - [Capture Groups](VerbalExpression/capture-groups) 18 | - [Miscellaneous](VerbalExpression/miscellaneous) 19 | 20 | ___ 21 | 22 | Methods have a return type of [`VerbalExpression`](VerbalExpressions) except where mentioned otherwise. If there is no mention of a method's parameters, it is to be assumed that it has none. 23 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "verbal-expressions", 3 | "description": "JavaScript Regular expressions made easy", 4 | "version": "1.0.2", 5 | "keywords": [ 6 | "regular expressions", 7 | "regex" 8 | ], 9 | "homepage": "https://github.com/VerbalExpressions/JSVerbalExpressions", 10 | "devDependencies": { 11 | "@babel/preset-env": "^7.12.1", 12 | "ava": "^3.13.0", 13 | "babel-core": "^6.26.3", 14 | "babel-plugin-transform-builtin-extend": "^1.1.2", 15 | "eslint": "^8.10.0", 16 | "eslint-config-airbnb": "^19.0.4", 17 | "eslint-plugin-import": "^2.22.1", 18 | "eslint-plugin-jsx-a11y": "^6.4.1", 19 | "eslint-plugin-react": "^7.21.5", 20 | "grunt": "^1.3.0", 21 | "grunt-ava": "^0.19.0", 22 | "grunt-babel": "^8.0.0", 23 | "grunt-contrib-uglify": "^5.0.0", 24 | "grunt-eslint": "^24.0.0", 25 | "grunt-markdownlint": "^3.1.0", 26 | "grunt-sourcemap-localize": "^0.1.0", 27 | "grunt-umd": "^3.0.0", 28 | "nyc": "^15.1.0" 29 | }, 30 | "repository": { 31 | "type": "git", 32 | "url": "git://github.com/VerbalExpressions/JSVerbalExpressions.git" 33 | }, 34 | "bugs": { 35 | "url": "https://github.com/VerbalExpressions/JSVerbalExpressions/issues" 36 | }, 37 | "main": "dist/verbalexpressions.js", 38 | "license": "MIT", 39 | "scripts": { 40 | "test": "grunt test", 41 | "test:verbose": "grunt test:verbose", 42 | "compile": "grunt compile", 43 | "grunt": "grunt", 44 | "build": "grunt build" 45 | }, 46 | "types": "./typings/VerbalExpressions.d.ts", 47 | "engines": { 48 | "node": ">=9.2.0" 49 | }, 50 | "dependencies": {}, 51 | "prettier": { 52 | "singleQuote": true 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /test/tests.js: -------------------------------------------------------------------------------- 1 | const test = require('ava'); 2 | const VerEx = require('../dist/verbalexpressions'); 3 | 4 | // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/test#Using_test()_on_a_regex_with_the_global_flag 5 | function resetLastIndex(regex) { 6 | regex.lastIndex = 0; 7 | } 8 | 9 | test('constructor', (t) => { 10 | const testRegex = VerEx(); 11 | 12 | t.true(testRegex instanceof RegExp, 'Should extend RegExp'); 13 | t.is(testRegex.toString(), '/(?:)/gm', 'Should be empty regex with global, multiline matching'); 14 | }); 15 | 16 | // Utility // 17 | 18 | test('sanitize', (t) => { 19 | const testString = '$a^b\\c|d(e)f[g]h{i}j.k*l+m?n:o=p'; 20 | const escaped = '\\$a\\^b\\\\c\\|d\\(e\\)f\\[g\\]h\\{i\\}j\\.k\\*l\\+m\\?n\\:o\\=p'; 21 | 22 | t.is(VerEx().sanitize(testString), escaped, 'Special characters should be sanitized'); 23 | 24 | t.is(VerEx().sanitize(42), 42); 25 | t.is(VerEx().sanitize(/foo/), 'foo'); 26 | 27 | t.notThrows(() => VerEx().sanitize()); 28 | t.notThrows(() => VerEx().sanitize(NaN)); 29 | t.notThrows(() => VerEx().sanitize(null)); 30 | t.notThrows(() => VerEx().sanitize(true)); 31 | }); 32 | 33 | test('add', (t) => { 34 | let testRegex = VerEx().startOfLine().withAnyCase().endOfLine(); 35 | testRegex = testRegex.add('(?:foo)?'); 36 | 37 | t.true(testRegex.source.startsWith('^'), 'Should retain old prefixes'); 38 | t.true(testRegex.source.endsWith('$'), 'Should retain old suffixes'); 39 | 40 | t.true(testRegex.test('foo'), 'Should add new rules'); 41 | resetLastIndex(testRegex); 42 | t.true(testRegex.test(''), 'Should add new rules'); 43 | 44 | t.true(testRegex.flags.includes('i'), 'Should retain old modifiers'); 45 | }); 46 | 47 | // Rules // 48 | 49 | test('startOfLine', (t) => { 50 | let testRegex = VerEx().startOfLine().then('a'); 51 | let testString = 'a'; 52 | 53 | t.true(testRegex.test(testString)); 54 | 55 | resetLastIndex(testRegex); 56 | testString = 'ba'; 57 | t.false(testRegex.test(testString)); 58 | 59 | testRegex = testRegex.startOfLine(false); // start of line is no longer necessary 60 | testString = 'ba'; 61 | t.true(testRegex.test(testString)); 62 | }); 63 | 64 | test('endOfLine', (t) => { 65 | let testRegex = VerEx().find('a').endOfLine(); 66 | let testString = 'a'; 67 | 68 | t.true(testRegex.test(testString)); 69 | 70 | resetLastIndex(testRegex); 71 | testString = 'ab'; 72 | t.false(testRegex.test(testString)); 73 | 74 | testRegex = testRegex.endOfLine(false); // end of line is no longer necessary 75 | testString = 'ab'; 76 | t.true(testRegex.test(testString)); 77 | }); 78 | 79 | function then(name, t) { 80 | let testRegex = VerEx()[name]('a'); 81 | let testString = 'a'; 82 | 83 | t.true(testRegex.test(testString)); 84 | 85 | resetLastIndex(testRegex); 86 | testString = 'b'; 87 | t.false(testRegex.test(testString)); 88 | 89 | resetLastIndex(testRegex); 90 | testString = ''; 91 | t.false(testRegex.test(testString)); 92 | 93 | testRegex = VerEx()[name]('a')[name]('b'); 94 | testString = 'ab'; 95 | t.true(testRegex.test(testString)); 96 | 97 | resetLastIndex(testRegex); 98 | testString = 'ac'; 99 | t.false(testRegex.test(testString)); 100 | } 101 | 102 | test('then', (t) => { 103 | then('then', t); 104 | }); 105 | 106 | test('find', (t) => { 107 | then('find', t); 108 | }); 109 | 110 | test('maybe', (t) => { 111 | const testRegex = VerEx().startOfLine().then('a').maybe('b'); 112 | let testString = 'acb'; 113 | 114 | t.true(testRegex.test(testString)); 115 | 116 | resetLastIndex(testRegex); 117 | testString = 'abc'; 118 | t.true(testRegex.test(testString)); 119 | }); 120 | 121 | test('or', (t) => { 122 | let testRegex = VerEx().startOfLine().then('abc').or('def'); 123 | let testString = 'defzzz'; 124 | 125 | t.true(testRegex.test(testString)); 126 | 127 | resetLastIndex(testRegex); 128 | testString = 'abczzz'; 129 | t.true(testRegex.test(testString)); 130 | 131 | resetLastIndex(testRegex); 132 | testString = 'xyzabc'; 133 | t.false(testRegex.test(testString)); 134 | 135 | testRegex = VerEx().startOfLine().then('abc').or().then('def'); 136 | testString = 'defzzz'; 137 | t.true(testRegex.test(testString)); 138 | 139 | resetLastIndex(testRegex); 140 | testString = 'abczzz'; 141 | t.true(testRegex.test(testString)); 142 | 143 | resetLastIndex(testRegex); 144 | testString = 'xyzabc'; 145 | t.false(testRegex.test(testString)); 146 | }); 147 | 148 | test('anything', (t) => { 149 | const testRegex = VerEx().startOfLine().anything(); 150 | let testString = 'foo'; 151 | 152 | t.true(testRegex.test(testString)); 153 | 154 | resetLastIndex(testRegex); 155 | testString = ''; 156 | t.true(testRegex.test(testString), 'Should be able to match zero characters'); 157 | }); 158 | 159 | test('anythingBut', (t) => { 160 | let testRegex = VerEx().startOfLine().anythingBut('br').endOfLine(); 161 | let testString = 'foobar'; 162 | 163 | t.false(testRegex.test(testString)); 164 | 165 | resetLastIndex(testRegex); 166 | testString = 'foo_a_'; 167 | t.true(testRegex.test(testString)); 168 | 169 | testRegex = VerEx().startOfLine().anythingBut('br'); 170 | testString = 'bar'; 171 | t.true(testRegex.test(testString), 'Should be able to match zero characters'); 172 | 173 | testRegex = VerEx().startOfLine().anythingBut(['b', 'r']).endOfLine(); 174 | testString = 'foobar'; 175 | t.false(testRegex.test(testString)); 176 | 177 | resetLastIndex(testRegex); 178 | testString = 'foo_a_'; 179 | t.true(testRegex.test(testString)); 180 | 181 | testRegex = VerEx().startOfLine().anythingBut(['b', 'r']); 182 | testString = 'bar'; 183 | t.true(testRegex.test(testString), 'Should be able to match zero characters'); 184 | }); 185 | 186 | test('something', (t) => { 187 | const testRegex = VerEx().something(); 188 | let testString = ''; 189 | 190 | t.false(testRegex.test(testString)); 191 | 192 | resetLastIndex(testRegex); 193 | testString = 'a'; 194 | t.true(testRegex.test(testString)); 195 | }); 196 | 197 | test('somethingBut', (t) => { 198 | let testRegex = VerEx().startOfLine().somethingBut('abc').endOfLine(); 199 | let testString = ''; 200 | t.false(testRegex.test(testString)); 201 | 202 | resetLastIndex(testRegex); 203 | testString = 'foo'; 204 | t.true(testRegex.test(testString)); 205 | 206 | resetLastIndex(testRegex); 207 | testString = 'fab'; 208 | t.false(testRegex.test(testString)); 209 | 210 | testRegex = VerEx().startOfLine().somethingBut(['a', 'b', 'c']).endOfLine(); 211 | testString = ''; 212 | t.false(testRegex.test(testString)); 213 | 214 | resetLastIndex(testRegex); 215 | testString = 'foo'; 216 | t.true(testRegex.test(testString)); 217 | 218 | resetLastIndex(testRegex); 219 | testString = 'fab'; 220 | t.false(testRegex.test(testString)); 221 | }); 222 | 223 | function anyOf(name, t) { 224 | let testRegex = VerEx().startOfLine().then('a')[name]('xyz'); 225 | let testString = 'ay'; 226 | 227 | t.true(testRegex.test(testString)); 228 | 229 | resetLastIndex(testRegex); 230 | testString = 'ab'; 231 | t.false(testRegex.test(testString)); 232 | 233 | resetLastIndex(testRegex); 234 | testString = 'a'; 235 | t.false(testRegex.test(testString)); 236 | 237 | testRegex = VerEx().startOfLine().then('a')[name](['x', 'y', 'z']); 238 | testString = 'ay'; 239 | 240 | t.true(testRegex.test(testString)); 241 | 242 | resetLastIndex(testRegex); 243 | testString = 'ab'; 244 | t.false(testRegex.test(testString)); 245 | 246 | resetLastIndex(testRegex); 247 | testString = 'a'; 248 | t.false(testRegex.test(testString)); 249 | } 250 | 251 | test('anyOf', (t) => { 252 | anyOf('anyOf', t); 253 | }); 254 | 255 | test('any', (t) => { 256 | anyOf('any', t); 257 | }); 258 | 259 | test('not', (t) => { 260 | const testRegex = VerEx().startOfLine().not('foo').anything().endOfLine(); 261 | let testString = 'foobar'; 262 | 263 | t.false(testRegex.test(testString)); 264 | 265 | resetLastIndex(testRegex); 266 | testString = 'bar'; 267 | t.true(testRegex.test(testString)); 268 | }); 269 | 270 | test('range', (t) => { 271 | let testRegex = VerEx().startOfLine().range('a', 'z', '0', '9').oneOrMore().endOfLine(); 272 | let testString = 'foobarbaz123'; 273 | 274 | t.true(testRegex.test(testString)); 275 | 276 | resetLastIndex(testRegex); 277 | testString = 'fooBarBaz_123'; 278 | t.false(testRegex.test(testString)); 279 | 280 | testRegex = VerEx().startOfLine().range('a', 'z', '0').oneOrMore().endOfLine(); 281 | testString = 'foobarbaz'; 282 | t.true(testRegex.test(testString)); 283 | 284 | resetLastIndex(testRegex); 285 | testString = 'foobarbaz123'; 286 | t.false(testRegex.test(testString), 'Should ignore extra parameters'); 287 | }); 288 | 289 | // Special characters // 290 | 291 | function lineBreak(name, t) { 292 | const testRegex = VerEx().startOfLine().then('abc')[name]().then('def'); 293 | let testString = 'abc\r\ndef'; 294 | 295 | t.true(testRegex.test(testString)); 296 | 297 | resetLastIndex(testRegex); 298 | testString = 'abc\ndef'; 299 | t.true(testRegex.test(testString)); 300 | 301 | resetLastIndex(testRegex); 302 | testString = 'abc\rdef'; 303 | t.true(testRegex.test(testString)); 304 | 305 | resetLastIndex(testRegex); 306 | testString = 'abc\r\n\ndef'; 307 | t.false(testRegex.test(testString)); 308 | } 309 | 310 | test('lineBreak', (t) => { 311 | lineBreak('lineBreak', t); 312 | }); 313 | 314 | test('br', (t) => { 315 | lineBreak('br', t); 316 | }); 317 | 318 | test('tab', (t) => { 319 | const testRegex = VerEx().startOfLine().tab().then('abc'); 320 | let testString = '\tabc'; 321 | 322 | t.true(testRegex.test(testString)); 323 | 324 | resetLastIndex(testRegex); 325 | testString = 'abc'; 326 | t.false(testRegex.test(testString)); 327 | }); 328 | 329 | test('word', (t) => { 330 | let testRegex = VerEx().startOfLine().word().endOfLine(); 331 | let testString = 'azertyuiopqsdfghjklmwxcvbn0123456789_'; 332 | 333 | t.true(testRegex.test(testString)); 334 | 335 | testRegex = VerEx().word(); 336 | testString = '. @[]|,&~-'; 337 | t.false(testRegex.test(testString)); 338 | }); 339 | 340 | test('digit', (t) => { 341 | let testRegex = VerEx().startOfLine().digit().oneOrMore().endOfLine(); 342 | let testString = '0123456789'; 343 | 344 | t.true(testRegex.test(testString)); 345 | 346 | testRegex = VerEx().digit(); 347 | testString = '-.azertyuiopqsdfghjklmwxcvbn @[]|,_&~'; 348 | t.false(testRegex.test(testString)); 349 | }); 350 | 351 | test('whitespace', (t) => { 352 | const testRegex = VerEx().startOfLine().whitespace().oneOrMore().searchOneLine().endOfLine(); 353 | let testString = ' \t\r\n\v\f'; 354 | 355 | t.true(testRegex.test(testString)); 356 | 357 | resetLastIndex(testRegex); 358 | testString = 'a z'; 359 | t.false(testRegex.test(testString)); 360 | }); 361 | 362 | // Modifiers // 363 | 364 | test('addModifier', (t) => { 365 | let testRegex = VerEx().addModifier('y'); 366 | t.true(testRegex.flags.includes('y')); 367 | 368 | t.notThrows(() => { 369 | testRegex = VerEx().addModifier('g'); 370 | }, 'Should not add extra modifier if it already exists'); 371 | }); 372 | 373 | test('removeModifier', (t) => { 374 | const testRegex = VerEx().removeModifier('g'); 375 | t.false(testRegex.flags.includes('g')); 376 | }); 377 | 378 | test('withAnyCase', (t) => { 379 | let testRegex = VerEx().startOfLine().then('a'); 380 | let testString = 'A'; 381 | 382 | t.false(testRegex.test(testString)); 383 | 384 | testRegex = VerEx().startOfLine().then('a').withAnyCase(); 385 | testString = 'A'; 386 | t.true(testRegex.test(testString)); 387 | 388 | resetLastIndex(testRegex); 389 | testString = 'a'; 390 | t.true(testRegex.test(testString)); 391 | 392 | testRegex = VerEx().startOfLine().then('a').withAnyCase(false); 393 | testString = 'A'; 394 | t.false(testRegex.test(testString)); 395 | }); 396 | 397 | test('stopAtFirst', (t) => { 398 | let testRegex = VerEx().find('foo'); 399 | const testString = 'foofoofoo'; 400 | 401 | t.is(testString.match(testRegex).length, 3, 'Should match all "foo"s'); 402 | 403 | testRegex = VerEx().find('foo').stopAtFirst(); 404 | t.is(testString.match(testRegex).length, 1, 'Should match one "foo"'); 405 | 406 | testRegex = VerEx().find('foo').stopAtFirst(false); 407 | t.is(testString.match(testRegex).length, 3, 'Should match all "foo"s'); 408 | }); 409 | 410 | test('searchOneLine', (t) => { 411 | let testRegex = VerEx().startOfLine().then('b').endOfLine(); 412 | const testString = 'a\nb\nc'; 413 | 414 | t.true(testRegex.test(testString)); 415 | 416 | testRegex = VerEx().startOfLine().then('b').endOfLine().searchOneLine(); 417 | t.false(testRegex.test(testString)); 418 | 419 | testRegex = VerEx().startOfLine().then('b').endOfLine().searchOneLine(false); 420 | t.true(testRegex.test(testString)); 421 | }); 422 | 423 | // Loops // 424 | 425 | test('repeatPrevious', (t) => { 426 | let testRegex = VerEx().startOfLine().find('foo').repeatPrevious(3).endOfLine(); 427 | let testString = 'foofoofoo'; 428 | 429 | t.true(testRegex.test(testString)); 430 | 431 | resetLastIndex(testRegex); 432 | testString = 'foofoo'; 433 | t.false(testRegex.test(testString)); 434 | 435 | resetLastIndex(testRegex); 436 | testString = 'foofoofoofoo'; 437 | t.false(testRegex.test(testString)); 438 | 439 | resetLastIndex(testRegex); 440 | testString = 'bar'; 441 | t.false(testRegex.test(testString)); 442 | 443 | testRegex = VerEx().startOfLine().find('foo').repeatPrevious(1, 3).endOfLine(); 444 | 445 | for (let i = 0; i <= 4; i++) { 446 | resetLastIndex(testRegex); 447 | testString = 'foo'.repeat(i); 448 | 449 | if (i < 1 || i > 3) { 450 | t.false(testRegex.test(testString)); 451 | } else { 452 | t.true(testRegex.test(testString)); 453 | } 454 | } 455 | 456 | testRegex = VerEx().startOfLine().find('foo').repeatPrevious().endOfLine(); 457 | testString = 'foofoo'; 458 | t.false(testRegex.test(testString), 'Should silently fail on edge cases'); 459 | 460 | testRegex = VerEx().startOfLine().find('foo').repeatPrevious(1, 2, 3).endOfLine(); 461 | testString = 'foofoo'; 462 | t.false(testRegex.test(testString), 'Should silently fail on edge cases'); 463 | }); 464 | 465 | test('oneOrMore', (t) => { 466 | const testRegex = VerEx().startOfLine().then('foo').oneOrMore().endOfLine(); 467 | let testString = 'foo'; 468 | 469 | t.true(testRegex.test(testString)); 470 | 471 | resetLastIndex(testRegex); 472 | testString = 'foofoo'; 473 | t.true(testRegex.test(testString)); 474 | 475 | resetLastIndex(testRegex); 476 | testString = 'bar'; 477 | t.false(testRegex.test(testString)); 478 | }); 479 | 480 | test('multiple', (t) => { 481 | let testRegex = VerEx().startOfLine().find(' ').multiple().endOfLine(); 482 | let testString = ' '; 483 | t.true(testRegex.test(testString)); 484 | 485 | resetLastIndex(testRegex); 486 | testString = ' a '; 487 | t.false(testRegex.test(testString)); 488 | 489 | testRegex = VerEx().startOfLine().multiple('foo').endOfLine(); 490 | testString = 'foo'; 491 | 492 | t.true(testRegex.test(testString)); 493 | 494 | resetLastIndex(testRegex); 495 | testString = 'foofoofoo'; 496 | t.true(testRegex.test(testString)); 497 | 498 | resetLastIndex(testRegex); 499 | testString = ''; 500 | t.true(testRegex.test(testString)); 501 | 502 | testRegex = VerEx().startOfLine().multiple('foo', 2).endOfLine(); 503 | testString = 'foo'; 504 | t.false(testRegex.test(testString)); 505 | 506 | resetLastIndex(testRegex); 507 | testString = 'foofoo'; 508 | t.true(testRegex.test(testString)); 509 | 510 | resetLastIndex(testRegex); 511 | testString = 'foofoofoo'; 512 | t.true(testRegex.test(testString)); 513 | 514 | testRegex = VerEx().startOfLine().multiple('foo', 2, 5).endOfLine(); 515 | 516 | for (let i = 0; i <= 6; i++) { 517 | resetLastIndex(testRegex); 518 | testString = 'foo'.repeat(i); 519 | 520 | if (i < 2 || i > 5) { 521 | t.false(testRegex.test(testString)); 522 | } else { 523 | t.true(testRegex.test(testString)); 524 | } 525 | } 526 | }); 527 | 528 | // Capture groups // 529 | 530 | test('capture groups', (t) => { 531 | let testRegex = VerEx().find('foo').beginCapture().then('bar'); 532 | let testString = 'foobar'; 533 | 534 | t.true(testRegex.test(testString), 'Expressions with incomplete capture groups should work'); 535 | 536 | testRegex = testRegex.endCapture().then('baz'); 537 | testString = 'foobarbaz'; 538 | t.true(testRegex.test(testString)); 539 | 540 | resetLastIndex(testRegex); 541 | const matches = testRegex.exec(testString); 542 | t.is(matches[1], 'bar'); 543 | }); 544 | 545 | // Miscellaneous // 546 | 547 | test('replace', (t) => { 548 | const testRegex = VerEx().find(' '); 549 | const testString = 'foo bar baz'; 550 | 551 | t.is(testRegex.replace(testString, '_'), 'foo_bar_baz'); 552 | }); 553 | 554 | test('toRegExp', (t) => { 555 | const testRegex = VerEx().anything(); 556 | const converted = testRegex.toRegExp(); 557 | 558 | t.is(converted.toString(), testRegex.toString(), 'Converted regex should have same behaviour'); 559 | }); 560 | -------------------------------------------------------------------------------- /typings/VerbalExpressions.d.ts: -------------------------------------------------------------------------------- 1 | // Type definitions for JSVerbalExpressions 2 | // Project: https://github.com/VerbalExpressions/JSVerbalExpressions 3 | // Definitions by: Mihai Ionut Vilcu 4 | // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped 5 | 6 | type RegExpFlags = "g" | "i" | "m" | "u" | "y"; 7 | type Appendable = VerbalExpression | RegExp | string | number; 8 | 9 | interface VerbalExpression extends RegExp { 10 | // Utility // 11 | /** Sanitation function for adding anything safely to the expression */ 12 | sanitize(value: Appendable): VerbalExpression; 13 | /** Append literal expression to the object. Also refreshes the expression. */ 14 | add(value: string | number): VerbalExpression; 15 | 16 | // Rules // 17 | /** Mark the expression to end at the last character of the line. */ 18 | startOfLine(enable?: boolean): VerbalExpression; 19 | /** Mark the expression to start at the beginning of the line. */ 20 | endOfLine(enable?: boolean): VerbalExpression; 21 | /** Add a string to the expression */ 22 | then(value: Appendable): VerbalExpression; 23 | /** Add a string to the expression. Alias for then() */ 24 | find(value: Appendable): VerbalExpression; 25 | /** Add a string to the expression that might appear once (or not). */ 26 | maybe(value: Appendable): VerbalExpression; 27 | /** Add a alternative expression to be matched. */ 28 | or(value?: Appendable): VerbalExpression; 29 | /** Match any character(s) any (including zero) number of times. */ 30 | anything(): VerbalExpression; 31 | anythingBut(value: Appendable | string[]): VerbalExpression; 32 | /** Match any character(s) at least once. */ 33 | something(): VerbalExpression; 34 | somethingBut(value: Appendable | string[]): VerbalExpression; 35 | /** Match any of the provided values */ 36 | anyOf(value: Appendable | string[]): VerbalExpression; 37 | /** Match any of the provided values. Alias for anyOf() */ 38 | any(value: Appendable | string[]): VerbalExpression; 39 | /** Ensure that the parameter does not follow. */ 40 | not(value: Appendable): VerbalExpression; 41 | /** Add expression to match a range (or multiply ranges) */ 42 | range(...values: string[]): VerbalExpression; 43 | 44 | // Special Characters 45 | /** Add universal line break expression */ 46 | lineBreak(): VerbalExpression; 47 | /** Add universal line break expression. Alias for lineBreak() */ 48 | br(): VerbalExpression; 49 | /** Add expression to match a tab character */ 50 | tab(): VerbalExpression; 51 | /** Add expression to match a word */ 52 | word(): VerbalExpression; 53 | /** Add expression to match a digit */ 54 | digit(): VerbalExpression; 55 | /** Add expression to match a whitespace character */ 56 | whitespace(): VerbalExpression; 57 | 58 | // Modifiers // 59 | /** Adds a modifier to the expression. */ 60 | addModifier(modifier: RegExpFlags): VerbalExpression; 61 | /** Removes a modifier to the expression. */ 62 | removeModifier(modifier: RegExpFlags): VerbalExpression; 63 | /** Makes the expression case insensitive */ 64 | withAnyCase(enable?: boolean): VerbalExpression; 65 | /** Removes the 'g' modifier. */ 66 | stopAtFirst(enable?: boolean): VerbalExpression; 67 | /** Removes the 'm' modifier. */ 68 | searchOneLine(enable?: boolean): VerbalExpression; 69 | 70 | // Loops // 71 | /** Repeat the previous item between mix and max (inclusive) times. */ 72 | repeatPrevious(min: number, max: number): VerbalExpression; 73 | /** Repeat the previous item exactly count times. */ 74 | repeatPrevious(count: number): VerbalExpression; 75 | /** Match the previous stuff one or more times. */ 76 | oneOrMore(): VerbalExpression; 77 | /** Match something greater than or equal to min number of times. Or of upper is set. Match something between min and max (inclusive) number of times. */ 78 | multiple(value: string, lower: number, upper?: number): VerbalExpression; 79 | /** Match something zero or more times. */ 80 | multiple(value: string): VerbalExpression; 81 | /** Match the previous group any number of times. */ 82 | multiple(): VerbalExpression; 83 | /** Starts a capturing group */ 84 | beginCapture(): VerbalExpression; 85 | /** Emds a capturing group */ 86 | endCapture(): VerbalExpression; 87 | 88 | // Miscellaneous 89 | replace(source: string, value: string): string; 90 | /** Converts the verbal expression to a RegExp object */ 91 | toRegExp(): RegExp; 92 | } 93 | 94 | interface VerbalExpressionConstructor { 95 | new(): VerbalExpression; 96 | (): VerbalExpression; 97 | prototype: VerbalExpression; 98 | } 99 | 100 | declare var VerEx: VerbalExpressionConstructor; 101 | export = VerEx; 102 | --------------------------------------------------------------------------------