SitePoint Sponsor

User Tag List

Results 1 to 7 of 7
  1. #1
    SitePoint Member
    Join Date
    Sep 2006
    Posts
    4
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    what's the JS equivalent of PHP preg_match_all ?

    I have a problem with a match in JS. Here is a page with both the PHP pattern and the match that works, as well as my attempts to do the same match with JS.

    http://christianfecteau.com/echo/match.php

    PHP Code:
    <?php
    $subject 
    '<select multiple="multiple" size="7" id="eci-anchor-menu" onchange="eci_anchor_selector.go()"><option value="#eci-anchor">Reset hash</option><option value="#a1">top of the page</option><option value="#a2">the second paragraph</option><option value="#a3">a third paragraph</option><option value="#a4">a fourth paragraph</option><option value="#a5">last one</option><option value="#a6">favlet not for IE</option></select>';

    $pattern "#<option.*?>(.*?)</option>#";

    preg_match_all($pattern$subject$matches);

    print_r($matches);
    ?>
    Code:
    $subject = '<select multiple="multiple" size="7" id="eci-anchor-menu" onchange="eci_anchor_selector.go()"><option value="#eci-anchor">Reset hash</option><option value="#a1">top of the page</option><option value="#a2">the second paragraph</option><option value="#a3">a third paragraph</option><option value="#a4">a fourth paragraph</option><option value="#a5">last one</option><option value="#a6">favlet not for IE</option></select>';
    
    $pattern = new RegExp("<option.*?>(.*?)</option>","g");
    
    //$matches = $pattern.exec($subject);
    $matches = $subject.match($pattern);
    
    document.writeln('<textarea style="width:100%;height:50%">JavaScript:');
    document.writeln($matches);
    document.writeln('</textarea>');
    I only the get the first match in JS, I can't get the second match.
    I've tried the match and exec methods, both with and without the g flag.

    So am I missing something?

  2. #2
    Programming Team silver trophybronze trophy
    Mittineague's Avatar
    Join Date
    Jul 2005
    Location
    West Springfield, Massachusetts
    Posts
    17,269
    Mentioned
    196 Post(s)
    Tagged
    2 Thread(s)

    regex matches

    Hi metaw3, welcome to the forums,
    It seems to me that the global "g" fllag is doing it's job (see the commas?)
    You may be better able to see what's going on with this.
    HTML Code:
    document.writeln('<textarea style="width:100%;height:50%">javascript:');
    for(var i = 0; i < $matches.length; i++)
    {
    document.writeln("match " + i + " is " + $matches[i]);
    }
    document.writeln('</textarea>');
    Although I suggest you spend a bit of effort refining your pattern. Remember "." means everything and anything, including other tags.

  3. #3
    SitePoint Member
    Join Date
    Sep 2006
    Posts
    4
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I'm sorry I wasn't clear enough with my question, but thank you for the reply and the greeting.

    I didn't formatted the JS output but I knew about the commas. My question was: "Is there a native function in JavaScript that will return, with the correct pattern, a 2 dimensional array like I do with PHP, or do I have to use 2 matches and to iterate and simulate preg_match_all?"
    Last edited by metaw3; Sep 19, 2006 at 20:20.

  4. #4
    Programming Team silver trophybronze trophy
    Mittineague's Avatar
    Join Date
    Jul 2005
    Location
    West Springfield, Massachusetts
    Posts
    17,269
    Mentioned
    196 Post(s)
    Tagged
    2 Thread(s)

    subpattern match

    Ah, I thought you meant it was only capturing the first option.
    To my knowledge there is no method in javascript that returns a multi-dimensional array of subpattern matches. You can use RegExp.$1, RegExp.$2 etc to get an array of subpattern matches from a single pattern match. I did work out a way to get such a multi-dimensional array.
    Rather than do a single match on the string, do repeated matching until the end of the string.
    HTML Code:
    $pattern = new RegExp("<option.*?>(.*?)</option>");
    
    document.writeln('<textarea style="width:100%;height:75%">javascript:');
    
    while($matches = $subject.match($pattern))
    {
    	$subject = RegExp.rightContext; /* ready for next match */
    
    	document.writeln("RegExp.lastMatch is " + RegExp.lastMatch); /* not Opera */
    	document.writeln("RegExp['$&'] is " + RegExp['$&']); /* not Opera */
    	document.writeln("match[0] is " + $matches[0]);
    	document.writeln("------------------------------------");
    	document.writeln("RegExp.lastParen is " + RegExp.lastParen); /* not Opera */
    	document.writeln("RegExp['$+'] is " + RegExp['$+']); /* not Opera */
    	document.writeln("RegExp.$1 is " + RegExp.$1);
    	document.writeln("match[1] is " + $matches[1]);
    	document.writeln("------------------------------------");
    }
    
    document.writeln('</textarea>');
    The 2 groups are "equivalents". I'm not sure how non-Windows OS browsers support the different properties. The "RegExp" properties didn't work in Opera 8.5 but maybe they do in the newer version? Anyway if you need the values in arrays, you could populate the arrays inside the while instead of writeln-ing.

  5. #5
    SitePoint Member
    Join Date
    Sep 2006
    Posts
    4
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Thumbs up Done

    Thank you sir. I applied your code to my example in the updated page linked in my first post. There are 3 textarea elements:
    1. PHP preg_match_all
    2. my workaround (using 2 patterns)
    3. your workaround (with one pattern, the same as with PHP) Great :)

    I paste it here for future readers:
    Code:
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
    <html>
    <head>
    <title>New Document</title>
    <meta http-equiv="Content-Type" 
    content="text/html; charset=iso-8859-1" />
    <script type="text/javascript">
    function niceFormat(obj)
    {
    	var out = '<textarea rows="30" style="width:100%">JavaScript:'+"\n\nArray\n(\n";
    	for (var i = 0; i < obj.length; i++)
    	{
    		out += ("\t["+i+"] => Array\n\t\(\n");
    		for (var j = 0; j < obj[i].length; j++)
    		{
    			out += ("\t\t["+j+"] => " + obj[i][j] + "\n");
    		}
    	}
    	out += "\t)\n)</textarea>";
    	return out;
    }
    </script>
    </head>
    <body>
    
    
    
    <!-- preg_match_all -->
    <div style="height:100%"><textarea rows="30" style="width:100%">PHP:
    <?php
    $subject = '<select multiple="multiple" size="7" id="eci-anchor-menu" onchange="eci_anchor_selector.go()"><option value="#eci-anchor">Reset hash</option><option value="#a1">top of the page</option><option value="#a2">the second paragraph</option><option value="#a3">a third paragraph</option><option value="#a4">a fourth paragraph</option><option value="#a5">last one</option><option value="#a6">favlet not for IE</option></select>';
    $pattern = "#<option[^>]*?>([^<]*?)</option>#";
    preg_match_all($pattern, $subject, $matches);
    
    
    // nice format
    print_r($matches);
    ?>
    </textarea>
    
    
    
    <!-- JS workaround -->
    <script type="text/javascript">
    $subject = '<?=$subject?>';
    $pattern1 = new RegExp("<option[^>]*?>[^<]*?</option>","g");
    $pattern2 = new RegExp("<option[^>]*?>([^<]*?)</option>","");
    $matches = [];
    $matches[0] = $subject.match($pattern1);
    $matches[1] = [];
    for (var i = 0; i < $matches[0].length; i++)
    {
    	$matches[1][i] = $matches[0][i].match($pattern2)[1];
    }
    
    // nice format
    document.write(niceFormat($matches));
    </script>
    
    
    
    <!-- Mittineague JS workaround -->
    <script type="text/javascript">
    $subject = '<?=$subject?>';
    $pattern = new RegExp("<option[^>]*?>([^<]*?)</option>");
    $matches = [[],[]];
    while($m = $subject.match($pattern))
    {
    	$subject = RegExp.rightContext; /* ready for next match */
    	$matches[0][$matches[0].length] = $m[0];
    	$matches[1][$matches[1].length] = $m[1];
    }
    
    // nice format
    document.write(niceFormat($matches));
    </script>
    
    
    
    </div>
    </body>
    </html>

  6. #6
    SitePoint Member
    Join Date
    Sep 2006
    Posts
    4
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Safari does not support RegExp.rightContext

    Quote Originally Posted by Mittineague
    $subject = RegExp.rightContext;
    Unfortunately, this above as well as RegExp["$'"] don't seem to be supported by Safari, and that is the browser for which I needed to match the pattern. The reason to "why Safari?" is that this browser don't support "Array.sort(compareFunc)" on strings if "compareFunc" uses properties of the a and b arguments to compare the strings. Like this:
    Code:
    ECI_anchor_selector.prototype.getMenuData = function(pageAnchors, sortValue)
    {
    	var out = [];
    	for (var i = 0, el; el = pageAnchors[i]; i++)
    	{
    		out[i] = {
    			value:	el.id ? el.id : el.name,
    			text:	el.title ? el.title : (el.id ? el.id : (el.name ? el.name : ''))
    		}
    	}
    	if (sortValue == true && !this.browsers.safari) { out.sort(this.sortByTextProperty); }
    	return out;
    }
    
    ECI_anchor_selector.prototype.sortByTextProperty = function(a, b)
    {
    	if (String(a.text).toLowerCase() < String(b.text).toLowerCase()) return -1;
    }
    So I had to use the "2 patterns" workaround.

    Here is what it was for:
    http://www.christianfecteau.com/echo...s/anchors.html

    It's fully functionnal with Firefox, Safari and Opera.

  7. #7
    Programming Team silver trophybronze trophy
    Mittineague's Avatar
    Join Date
    Jul 2005
    Location
    West Springfield, Massachusetts
    Posts
    17,269
    Mentioned
    196 Post(s)
    Tagged
    2 Thread(s)

    2 pattern solution

    I had started to work on a 2 pattern technique, but thought that it was starting to look like a bit more code than needed, and then worked out the 1 pattern way. Of course, without a Mac I could only hope that it would be supported. Oh well, darn cross-browser issues strike again. They sure can keep us busy As long as solutions can be found (even if a bit bloated), I guess it's just part of the job.


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •