JavaScript : Simple RegExp wrapper called ExpReg
by Developer @ pebbl.co.uk on Saturday, 27 April 2013
I just put this miniature library together to help work with Regular Expressions in a cleaner and abstracted manner. It's pretty simple, but RegExp interaction in JavaScript has always been a little clunky in my opinion, so it doesn't take much to smooth things out a little.
/// example usage
var result =
ExpReg(/\|/gi)
.haystack('[believe|dont]|[either,way]')
.replace(function(match, i){return '{'+i+'}';})
.haystack()
;
/// result = '[believe{8}dont]{14}[either,way]'
Whilst the above may actually be shorter to type in pure JavaScript:
String('[believe|dont]|[either,way]')
.replace(/\|?(\[[^\]]+\])/gi, function(match, i){
return '{'+i+'}';
})
;
.. the problem with the above is that it is completely different from the formation to step through items matched, for example:
var m, re = /\|?(\[[^\]]+\])/gi;
while( (m = re.exec('[believe|dont]|[either,way]')) ) {
/// do whatever processing required here.
};
The main benefit of using ExpReg would be that the way of dealing with Regular Expressions is standardised, and all the RegExp objects that are created are remembered, so you can refer back to them quickly — useful in code that reuses expressions. Plus it's easy to add new methods that work in a builder fashion — similar to jQuery.
/// another example using a string instead of literal RegExp
ExpReg('/./gi')
.haystack('this should match every letter')
.each(function(match, i){alert(i)})
;
/// an example of mapping
var words =
ExpReg(/\w+/gi)
.haystack('this should match every word')
.map(function(match){return match})
;
Just in case it comes in useful, here is the recently imagined source code of expreg.js :)
/**
* ExpReg 0.1
*
* ExpReg is just a simple RegExp wrapper that has some useful
* functions for dealing with Regular Expressions. This include
* is designed to work with require.js but can also operate as
* a normal js include.
*
* @author Phil Glanville - 2013/05
*/
var ExpReg;
/// define not-exist fallback
(typeof define === 'undefined' &&
(define=function(a){return (ExpReg = a())}));
/// hook into require.js
define(function(){
"use strict";
var global = {
delims: new RegExp('^([^a-z0-9\s])(.+?)\\1([gimy]{0,4})$','i'),
lookup: {}
};
/**
* The outer wrapping constructor that will be exposed as ExpReg
*/
var ExpReg = function(re, haystack){
var t;
if ( this instanceof ExpReg ) {
if ( !global.lookup[re] ) {
if ( re instanceof RegExp ) {
global.lookup[re] = re;
}
else if ( (t = global.delims.exec(re)) ) {
global.lookup[re] = new RegExp(t[2],t[3]);
}
}
this.exp = global.lookup[re];
this.source = haystack?haystack:'';
this.matches = [];
this.matched = false;
this.reversed = false;
}
else {
if ( typeof this == 'string' ) {
return new ExpReg(re, ''+this);
}
else {
return new ExpReg(re, haystack);
}
}
};
/**
* Simple jQuery like attr function
*/
ExpReg.prototype.attr = function( name, value ){
if ( arguments.length == 2 ) {
this.exp[name] = value;
}
else {
return this.exp[name];
}
};
/**
* Define the haystack that the RegExp will search
*/
ExpReg.prototype.haystack = function(string){
if ( arguments.length && (typeof string == 'string') ) {
this.source = string;
this.matched = false;
return this;
}
else {
return this.source;
}
};
/**
* Return a particular matched item. A matched item will
* be an object that contains a zero-indexed array of .groups
* and an .offset property that gives the start of where the
* match was found.
*/
ExpReg.prototype.item = function(n){
if ( arguments.length == 0 || n === undefined || n === null ) {
return this.matches;
}
else if ( n < 0 ) {
return this.matches[this.matches.length+n];
}
else if ( n < this.matches.length ) {
return this.matches[n];
}
else {
return null;
}
};
/**
*
*/
ExpReg.prototype.findAll = function(){
/// remove previously found items
this.matches.length = 0;
/// reset and scan
var groups; this.exp.lastIndex = 0;
/// if we are global we can findAll
if ( this.exp.global ) {
while( (groups = this.exp.exec(this.source)) ) {
this.matches[this.matches.length] = {
groups: groups,
offset: this.exp.lastIndex-groups[0].length
};
}
}
/// if not global, match the first and stop
else {
this.matches[this.matches.length] = {
groups: (groups = this.exp.exec(this.source)),
offset: this.exp.lastIndex-groups[0].length
};
}
///
this.matched = true;
};
/**
* Replace current selection with either string or result of callback
*/
ExpReg.prototype.replace = function(param){
if ( !this.matched ) { this.findAll(); }
if ( this.matches.length ) {
if ( typeof param == 'string' ) {
this.source = this.source.replace(this.exp, param);
}
else if ( param.call ) {
var exrg = this;
this.source = this.source
.replace(this.exp, function(a,b){return param(a,b,exrg)});
}
}
return this;
};
/**
* Call a callback for each match found
*/
ExpReg.prototype.each = function(callback){
if ( !this.matched ) { this.findAll(); }
if ( this.matches.length ) {
var i, l = this.matches.length;
for( i = 0; i < l; i++ ) {
callback.call(this, this.matches[i], i, this);
}
}
return this;
};
/**
* Map the matches to an array
*/
ExpReg.prototype.map = function(callback){
var a = [];
if ( !this.matched ) { this.findAll(); }
if ( this.matches.length ) {
var i, l = this.matches.length;
if( typeof callback == 'undefined' ) { callback = 1; }
if ( callback.call ) {
for( i = 0; i < l; i++ ) {
a[i] = callback.call(this, this.matches[i], i, this);
}
}
else {
for( i = 0; i < l; i++ ) {
if ( this.matches[i] &&
typeof this.matches[i].groups[callback] != 'undefined' ){
a[i] = this.matches[i].groups[callback];
}
}
}
}
return a;
};
/**
* wrap the matches with strings
*/
ExpReg.prototype.wrap = function(pre, post){
this.replace(function(match){
return pre+match+post;
});
return this;
};
ExpReg.prototype.reverse = function(){
if ( !this.matched ) { this.findAll(); }
this.matches.reverse();
this.reversed = !this.reversed;
return this;
};
/**
* debug log
*/
ExpReg.prototype.log = function(pre, post){
this.each(function(match, i){
console.log(i, match);
});
return this;
};
String.prototype.ExpReg = ExpReg;
return ExpReg;
});
/// remove our temporary define fallback
(ExpReg) && (define = undefined);
- Leave your comment • Category: Coding, JavaScript
- Share on Twitter, Facebook, Delicious, Digg, Reddit