Using Prototype’s New String Functions
August 29, 2006
After years of extensive research and study, I’ve come to a profound conclusion — working with strings sucks. It’s even more difficult when you’re doing it in JavaScript. Lucky for us, the Prototype JavaScript framework provides several shiny new String object functions to make our lives easier. Sounds like a perfect chance to be lazy — let’s get to work!
Note: I’m working with the new String methods in Prototype 1.5.
Let’s create a simple string we can run some manipulations on:
var string = 'Laziness always pays off now.';
String.gsub
The gsub method is similar to the native replace method, but it’s even more powerful. It accepts 2 arguments, the first one being the pattern to search for. This can be a simple string or a regular expression. The second argument is what to replace the matched pattern with.
Let’s start with something easy. I’m tired of spaces, so let’s replace them with underscores.
string.gsub(' ', '_');
// Returns "Laziness_always_pays_off_now."
Not very exciting, and we could have accomplished the same thing with string.replace(/\s/g, '_'). Where gsub really starts to shine is when you realize that the second argument can be a function. This function will run on each match found in the string. The function receives one argument, an array of matches against the pattern. You then return a manipulated version of the string. Sound confusing? Follow the bouncing code:
string.gsub(/\s\w/, function(match){ return match[0].toUpperCase(); });
// Returns "Laziness Always Pays Off Now."
Each match is passed to the function, which can then manipulate the match and return the version to replace. We needed to reference the match as match[0] because the matches of a regular expression are returned as an array. Index 0 is the entire match, and each numeric index after that corresponds to a parenthesis group in the regular expression. If we had used parenthesis in the regular expression, we could have accessed other elements of the match array:
string.gsub(/(s|f)(\s)/, function(match){ return match[1].toUpperCase() + '-' + match[2]; });
// Returns "LazinesS- alwayS- payS- ofF- now."
String.sub
String.sub is almost identical to String.gsub, but it accepts an additional argument. Instead of replacing each match in the string, sub replaces the number of matches that you pass in as the optional 3rd argument (which defaults to 1). Let’s return to our original example:
string.sub(' ', '_');
// Returns "Laziness_always pays off now."
This time, only the first match was replaced. If we run it again and pass in the 3rd parameter we’ll see something different:
string.sub(' ', '_', 3);
// Returns "Laziness_always_pays_off now."
Otherwise String.sub is identical to String.gsub.
String.scan
The scan method simply calls the String’s gsub method with the pattern and iterator function provided. This lets you loop through each match and do something with it:
string.scan(/\w+/, alert);
// Produces 5 alerts: "Laziness", "always", "pays", "off", "now"
Another use would be to get an array of all the items that matched:
var results = [];
string.scan(/\w+/, function(match){ results.push(match[0].toUpperCase()); });
// results = ['LAZINESS', 'ALWAYS', 'PAYS', 'OFF', 'NOW']
For some reason, the scan method returns the String object split into an array of its characters.
String.truncate
This method works almost like you’d expect, with a slight quirk (in my opinion). The truncate method chops a string off to the number of characters you supply as the first argument:
string.truncate(15);
// Returns "Laziness alw..."
That’s almost what I expected to get, except there are only 12 characters from the original string instead of 15. That’s because there’s an optional second argument to truncate to append to the end of the string, and it counts as part of the returned string’s length. It defaults to ‘…’, but the following will yield the result I expected to see:
string.truncate(15, '');
// Returns "Laziness always"
Template Class
Last we have a new Template class, which I think is a work of beauty. This class lets you set up a string template with variables to replace later, much like a PHP template or the server technology of your choice. The default variable substitution pattern is: #{variable_name}. Here’s how to create an object with the class:
var linkTemplate = new Template('<a href="#{href}">#{text}</a>');
You render the template by calling its evaluate method and passing in an object with property names matching the variables you used in the template:
linkTemplate.evaluate({href: 'http://www.google.com', text: 'The omnipotent one'});
// Returns "<a href="http://www.google.com">The omnipotent one</a>"
It also works with an array:
var arrayTemplate = new Template('Original: #{0}, Sequel: #{1}');
arrayTemplate.evaluate(['Naked Gun', 'Naked Gun 2 1/2']);
// Returns "Original: Naked Gun, Sequel: Naked Gun 2 1/2"
Customizing the Template Variable Pattern
Just because we can, let’s customize the Template class even further. Say you’ve already got a nice template, but it’s written in PHP using a short tag syntax. Being the lazy programmer you are, you can’t be bothered with rewriting this. Don’t worry, your hard work now will pay off with the potential for laziness later!
The second parameter to Template’s constructor is the regular expression pattern to use for the variable substitution. This parameter is optional and defaults to the Template.Pattern constant, which allows for the very nice #{variable} syntax. We can create our own regular expression to use for template variable substitution. Try the following:
Template.PhpPattern = /(^|.|\r|\n)(<\?=\s*\$(.*?)\s*\?>)/;
Now we can pull in a typical PHP template and let Prototype work its magic:
var phpTemplate = new Template('<div id="<?= $id ?>" class="<?= $class ?>"><?= $content ?></div>', Template.PhpPattern);
phpTemplate.evaluate({id: 'news', class: ['updated', 'arbitrary'].join(' '), content: '<p>No news is good news...</p>'});
// Returns "<div id="news" class="updated arbitrary"><p>No news is good news...</p></div>"
This might be useful if you are doing Ajax calls and returning JSON data a lot. You could create a Template class when the page loads using a small PHP template from your own site, then pass the JSON object you got from the Ajax request into the template’s evalute method. Of course, only do this if the PHP template file does not have any business/application logic that you don’t want prying eyes to see. Just remember that anything you give to JavaScript can be viewed by everyone. I recommend it only for simple templates that have simple variables, if you use it at all. You have been warned.
Even though I personally prefer to use simple PHP templates, I’ll give you a Smarty pattern to play with as well:
Template.SmartyPattern = /(^|.|\r|\n)(\{\$(.*?)\})/;
One important thing to note is that you should follow the existing Template.Pattern regular expression pattern’s structure of parenthesis. This structure follows one group to match before the variable, one group to match around the variable name, and the variable name itself. If you don’t follow the (beforePattern)(varSyntax(varName)) pattern, the template won’t replace your variable properly, because it relies on these parenthesis for the 1, 2, and 3 indexes.
Coming Full Circle
Now that I’ve shown you the Template class, I can put a nice cherry on top by showing you one more trick with String.gsub and String.sub. The second argument to these methods can also be a Template string:
string.gsub(/\s/, '#{0}_');
// Returns "Laziness _always _pays _off _now."
When using a template string as the second parameter, keep in mind that the match’s index works just like the index of the array that would be passed if the second argument was a function. Here’s an example:
'Cory Hudson'.gsub(/(\w+) (\w+)/, '#{2}, #{1}');
// Returns "Hudson, Cory"
Note that this Template pattern cannot be customized like it can be when you create an object from the Template class, so you’ll have to stick to the Ruby syntax when using gsub and sub. But emulating Ruby’s not such a bad thing, is it?
Strings Can Be Fun!
Even I had fun using Prototype’s latest additions to the native String object. They can save you some time while coding, and the fact that they are so flexible with their arguments is a nice bonus!
August 29th, 2006 at 6:07 pm
Great post.
Especially liked the bit about the template class (which I had never used before).
I really think we should start a general effort to document Prototype properly. There’s lots of good documentation around the internet. It just needs to be centralized somewhere.
I wonder if people would be willing to donate the tutorials/docs they have written to such an effort. Would you?
August 29th, 2006 at 6:35 pm
@Tobie: I’d be interested in helping with a central documentation site. I actually wrote this post while I was plowing through all the Prototype code to try creating some sort of initial documentation on my own site. I don’t have anything written yet because I wrote this post instead, but I agree that we need documentation. The lack of documentation makes us miss out on some of the power of the framework, and hinders new users from learning at a faster pace.
August 29th, 2006 at 10:31 pm
I’m down with a documentation effort. Tell me where and when to show up and I’ll be there.
August 29th, 2006 at 10:56 pm
[…] Cory Hudson covers some of the new string functions in Prototype 1.5. (via snook.ca). […]
August 30th, 2006 at 1:12 am
@Tobie, Cory,Andrew: Are you familiar with the “Developer Notes” for prototype.js? It’s the best documentation i’ve seen so far for prototype, and I use it regularly. Perhaphs you can just help with the updates for version 1.5
http://www.sergiopereira.com/articles/prototype.js.html
August 30th, 2006 at 8:37 am
[…] Using Prototype’s New String Functions: ”After years of extensive research and study, I’ve come to a profound conclusion — working with strings sucks. It’s even more difficult when you’re doing it in JavaScript. Lucky for us, the Prototype JavaScript framework provides several shiny new String object functions to make our lives easier. Sounds like a perfect chance to be lazy — let’s get to work! […]
August 30th, 2006 at 9:54 am
Nice!
I just did a little writeup on protype and have come to the conclusiong that Protype is my overlord.. (as well as the current savior of the web as we know it).. This is good info, will be passing this link around to some developers who need to read it
August 31st, 2006 at 1:12 pm
[…] If you want, you can also use your templates from javascript as well. I have some big plans and loads of ideas for ways to use JSON and prototype. […]
September 2nd, 2006 at 1:53 am
[…] Using Prototype’s New String Functions | CoryHudson.com The gsub method is similar to the native replace method, but it’s even more powerful. It accepts 2 arguments, the first one being the pattern to search for. This can be a simple string or a regular expression. The second argument is what to replace the (tags: javascript prototype strings) […]
September 6th, 2006 at 10:14 am
[…] using prototype’s new string functions […]
September 14th, 2006 at 11:19 am
hmm, how is gsub any different from replace?
currently implemented versions of javascript in modern browsers support replace used, just like gsub, first argument a RegExp object and the second a string or function.
instead of:
string.gsub(/\s\w/, function(match){ return match[0].toUpperCase(); });
do this:
string.replace(/\s\w/, function () { return arguments[0].toUpperCase(); });
what’s the “new” about it? improved backward compatibility for older browsers? :/
October 31st, 2006 at 5:30 pm
[…] Using Prototype’s New String Functions | CoryHudson.com (tags: javascript prototype) […]
February 5th, 2007 at 4:26 am
Hi,
I am building a new site in Hebrew using prototype.js
Everything works fine, but not the
new Ajax.Request(’./nextPage.php’, {method:’post’,….
In nextPage.php I get strange character although I added
header(’Content-Type: text/html; charset=WINDOWS-1255′); in the start of the PHP.
Do you know if and how I can specify the Ajax.Request to use charset=WINDOWS-1255?
Thanks and Best regards,
Eylon
The site which I am building: http://www.yaldut.com
April 1st, 2007 at 8:59 pm
nice site
April 25th, 2007 at 5:33 am
Thank You
September 12th, 2007 at 6:59 am
Hi
Check out a funny video :
http://www.youtube.com/watch?v=Z7jUnptjqZE
See you!
maik midlooks
September 13th, 2007 at 10:10 pm
hot videos
sex
September 21st, 2007 at 3:38 pm
In a life there are situations when anything except for thacher hamlin cannot help.
In other case don’t worry!
September 22nd, 2007 at 12:11 am
budesonide
…
http://hometown.aol.com/fantastic4pharm/budesonide budesonide
…
September 28th, 2007 at 9:55 am
lv
…
http://webtop4u.ifrance.com/lv lv
…
September 29th, 2007 at 1:46 pm
ftd
…
http://topwebs4u.ifrance.com/ftd ftd
…
September 30th, 2007 at 4:05 pm
buy.com…
http://topwebs4u.ifrance.com/buy.com buy.com…
October 10th, 2007 at 7:16 pm
adt
…
http://onlineis.googlegroups.com/web/adt.html adt
…
October 20th, 2007 at 2:10 am
internet access provider
…
http://iwebs5.webng.com/internet-provider internet access provider
…
October 20th, 2007 at 4:49 am
lanyard
…
http://iwebs5.webng.com/lanyard lanyard
…
October 23rd, 2007 at 8:29 am
I want to share this tip:
I know there is someone out there like me that tried and failed to download movies and http://how-to-burn-dvd.com - Burn DVD’s from the internet that play on a regular DVD player.
Thanks,
October 24th, 2007 at 4:08 am
topamax
…
http://livegroup.webng.com/topamax topamax
…
October 27th, 2007 at 9:44 pm
What is the big deal with these Zwinkys? I don’t know why, but people are going crazy over these things! will some zwinky lover please step and to explain what we’re
missing.
Thanks
October 27th, 2007 at 10:45 pm
ged
…
http://allweb.webng.com/ged ged
…
October 28th, 2007 at 3:27 pm
Hello Men’s
you must trasted
October 30th, 2007 at 4:28 am
timberland boots
…
http://monolit.webng.com/timberland-boots timberland boots
…
November 2nd, 2007 at 3:35 am
Hello
stgdgedr
restartos
November 3rd, 2007 at 4:18 am
dress game sexy
November 4th, 2007 at 10:28 am
culos abiertos
November 7th, 2007 at 8:46 pm
jcpenneys
…
http://top77webs.tripod.com/jcpenneys jcpenneys
…
November 8th, 2007 at 10:55 am
[…] read more | digg story […]
November 9th, 2007 at 4:31 am
ged
…
http://www.geocities.jp/top16line/ged ged
…
November 10th, 2007 at 8:59 pm
ftd
…
http://www.geocities.jp/top15webs/ftd ftd
…
November 13th, 2007 at 10:21 am
christmas wreaths
…
http://www.geocities.jp/christmas_line/christmas-wreaths christmas wreaths
…
November 14th, 2007 at 5:06 am
4 novembre anniv
ersario vittoria
November 15th, 2007 at 3:16 am
christmas presents
…
http://christmas.x10hosting.com/christmas-presents christmas presents
…
November 15th, 2007 at 8:27 am
verizon wireless
…
http://www.geocities.jp/best_topstore/verizon-wireless verizon wireless
…
April 2nd, 2008 at 12:02 am
poker en ligne jeu de poker en ligne…
…
April 2nd, 2008 at 2:00 am
application aspire card credit…
…
April 2nd, 2008 at 3:52 am
poker ohne internet…
…
April 2nd, 2008 at 6:06 am
giochi carte poker gratis…
…
April 2nd, 2008 at 1:23 pm
casino poker spielen…
…
April 2nd, 2008 at 2:20 pm
besten casino online…
…
April 2nd, 2008 at 3:01 pm
24 ringtones show tv…
…
April 2nd, 2008 at 3:28 pm
jeux poker online…
…
April 2nd, 2008 at 4:33 pm
jeu de poker en reseau…
…
April 2nd, 2008 at 5:56 pm
regeln für poker texas…
…
April 2nd, 2008 at 6:57 pm
www casino on line…
…
April 2nd, 2008 at 9:56 pm
giochi online di poker…
…
April 7th, 2008 at 5:49 pm
descargar juegos de poker gratis…
At this point online poker tour card credit discover payment…
May 3rd, 2008 at 12:09 am
online poker odds…
Eventually poker on line poker ligne gratuites…
May 5th, 2008 at 4:00 pm
casinos descargas portal web…
Manana jugar apostar linea ruleta europea portales internet…