JavaScript regexps for Perlers

TorgoX on 2005-07-14T09:07:49

Dear Log,

Here's my little phrasebook for converting common Perl RE idioms to JavaScript:

- - - - - - -
Perl idiom:
if( $x =~ m/fee(fie)foe(fum)/ ) {
  print "Yup!";
}

if( x.match( /fee(fie)foe(fum)/ ) ) {
  alert("Yup!");
}
- - - - - - -
Perl idiom:
if( $x =~ m/fee(fie)foe(fum)/ ) {
  print "$1$2";
}
var m = x.match( /fee(fie)foe(fum)/ );
if(m) {  alert(m[1] + m[2]);  }
- - - - - - -
Perl idiom:
$x =~ s/([a-j])/X/g;
x = x.replace( /([a-j])/g , "X" );
- - - - - - -
Perl idiom:
$x =~ s/([a-j])/X$1/g;
x = x.replace( /([a-j])/g , "X$1" );
- - - - - - -
Perl idiom:
$x =~ s/([a-j])/$funky{$1}/g;
x = x.replace( /([a-j])/g ,
  function(x) { return funky[x]; } 
);
- - - - - - -
Perl idiom:
@y = ($x =~ m/([a-j]+)/g);
y = x.match( /([a-j]+)/g ) || [];
- - - - - - -
Perl idiom:
$x =~ tr/a-j/0-9/
or
$y = $x =~ tr/a-j/0-9/;
Use a regexp replacement, as with the "funky" example above.
- - - - - - -
Perl idiom:
while( $x =~ m/(f.)/g ) {
  print "Zonk! $1 at ", pos($x), "!\n";
}
var x = "fee fie foe fum";
var re = /(f.)/g;
while(1) {
  var m = re.exec(x);
  if(!m) break;
  print("Zonk! " + m[1] + " at " +
   re.lastIndex.toString() + "!\n");
}
- - - - - - -
Perl idiom:
$y = quotemeta($x);
y = x.replace( /([^A-Za-z0-9])/g , "\\$1" );
- - - - - - -
Perl idiom:
$x = qr/$y/;
x = new RegExp(y);

- - - - - - -

This leads us to an interesting problem: suppose I have a hash in x, whose keys are string-values to replace, and the value for each is the string value that should be put in instead; and I want to perform replacement based on that.

var i = "the poppy is popular with pop stars?";
var map = { 'popular': 'fashionable',
  'pop': 'fun', 'poppy':'flower', "?":"!"
};

alert(super_replace(i, map));
// shows: "the flower is fashionable with fun stars!"

function super_replace (s, map) {

  var re_bits = [];
  for(var k in map) { re_bits.push(k) }
  if(!re_bits.length) return s;

  re_bits.sort( _for_re );
  for(var i = 0; i < re_bits.length; i++ ) {
    re_bits[i] = quotemeta( re_bits[i] );
  }
  var re = new RegExp( "(" +
    re_bits.join("|") + ")", 'g' );

  return s.replace( re,
   function (bit) { return map[bit] } );
}

function quotemeta (s) {
  return s.replace( /([^a-zA-Z0-9])/g, "\\$1" );
}

function _for_re (a,b) {  // longest-first
 return(
   (a.length > b.length) ? -1
 : (a.length < b.length) ?  1
 : (a < b) ? -1
 : (a > b) ?  1
 : 0
 );
}
That super_replace function is handy -- notably, most uses of tr/// are just a special case of it.


Another way...

bart on 2005-07-16T10:32:09

Perl idiom:
while( $x =~ m/(f.)/g ) {
  print "Zonk! $1 at ", pos($x), "!\n";
}
var x = "fee fie foe fum";
var re = /(f.)/g;
while(1) {
  var m = re.exec(x);
  if(!m) break;
  print("Zonk! " + m[1] + " at " +
    re.lastIndex.toString() + "!\n");
}

Javascript doesn't allow variable declarations inside the while condition expression, so you have to declare it outside the loop block:

var x = "fee fie foe fum";
var re = /(f.)/g;
var m;
while(m = re.exec(x)) {
  print("Zonk! " + m[1] + " at " +
    re.lastIndex.toString() + "!\n");
}

BTW print in my browser tries to print to the printer. Uh.

Re:Another way...

TorgoX on 2005-07-17T08:43:08

Ohyeah, I avoid assignment in conditions altogether -- I think it generates warnings somewhere or other. It's an annoyance, but I don't mind much.

As to print(), I reassigned it in my console, and I think it's the same in Venkman too. Anyhow, I forgot that I left in a usage of it in my example.