Regular Expressions are a powerful tool that you can utilize in many different programming languages. After throwing together the little twitter widget at the top of this page - I was informed by Brian Shaler of a major bug that causing it to crash. So while reworking the code to fix it I figured I’d add some much needed functionality as well. You see, just grabbing the feed from twitter does not generate html links for you. You have to parse your feed and wrap any ‘@username’ responses, or ‘http://addresses’ into actual hyperlinks yourself. Here’s how I did it.
Finding the @usernames and HTTP Addresses
So this is where we actually utilize RegExp. In Flash RegEx works very similar to other programming languages. You simply define a new variable as a with :RegExp class and then assign it a pattern. I used two separate patterns, one matches users, the other matches the http addresses. I won’t go into detail on explaining the RegEx patterns itself here as that is an entirely different topic. What I’m focusing on here is how to implement them in flash. But just for the heck of it, incase you want to take tese and make them better here are the two regular expression patterns I wrote:
- ‘@usernames’:
/(\s@+\w*(\s|,|!|\.|\n))/ - ‘http://…’:
/[^"|^>](http:\/\/+[\S]*)/
So here is the actual code I use in the widget above. The only difference is the ‘cur’ variable on the first line passes the current title from the twitter RSS feed instead of the dummy string I’ve hardcoded:
private function dropRSS():void {
var cur:String = "Hey @sunnythaper, @shalerjump, @jamesarcher! Check this out: http://tinyurl.com/377owu"
if (cur.substr(0,1) == "@") { // Skip response messages as they do not always provide enough context to be stand alone statements.
_current++;
dropRSS();
} else {
cur = cur+" "; // Append a space at the end so RegEx catches trailing expressions
var twitterUser:RegExp = /(\s@+\w*(\s|,|!|\.|\n))/; // "
var url:RegExp = /[^"|^>](http:\/\/+[\S]*)/;
while(twitterUser.exec (cur) != null) {
cur = cur.replace(twitterUser, pointToUser);
}
while(url.exec (cur) != null) {
cur = cur.replace(url, setUrl);
}
twit.htmlText = cur;
TweenLite.from(twit, 2, {ease:Elastic.easeOut, y:"-10", alpha: 0});
_current++;
}
}
What’s important to take note of is two things: 1) I need to loop and execute the pattern onto the string until it no longer finds any matches 2) I’m passing a function as the second parameter in the replace method as opposed to an alternate string.
- This has worked great but fundamentally I think there is a more efficient way of doing this without looping and executing the RegEx so many times.
- If you know a better way let me know and I’ll update this post.
Implementing Changed on Your Matches
As I said, I’m passing a function to actual handle the replacement as opposed to just passing a replacement string. This is because I need to run some processes on the matches to build urls based off of them. Flash lets you reference the matches in the functions as arguments. Here is the code.
private function pointToUser():String {
return " <a href=\"http://twitter.com/"+arguments[1].substr(2,arguments[1].length-3)+"\">"+arguments[1].substr(1,arguments[1].length-2)+"</a>"+arguments[1].substr(arguments[1].length-1,1);
}
private function setUrl():String {
return " <a href=\""+arguments[1]+"\">"+arguments[1]+"</a>";
}
Of course, if the RegEx pattern generated two or three differently matched terms you could reference them as well via arguments[2], arguments[3] etc.. Here you can do whatever you want. I chose to disect the one argument I was working with through a series of substring routines to trim out unwanted characters in certain parts and then re-insert them outside of the html.
Russell Heimlich Says:
11:53 amMar 02Regular expressions can be tricky so I use this hnady testing tool. http://design215.com/toolbox/regexp.php
Jim Jeffers Says:
12:15 pmMar 02@Russell - thanks for the link! That web based tool will definitely come in handy. Adding it to my magnolia now!
joshspoon Says:
11:23 pmMar 16Hey I don’t understand the:
# if (cur.substr(0,1) == “@”) { // Skip response messages as they do not always provide enough context to be stand alone statements.
# _current++;
# dropRSS();
# }
I get errors when it trys to redo the dropRSS.
by the way I’m passing in a string (dropRSS(status.text));
Jim Jeffers Says:
11:31 pmMar 16@joshspoon - Ah that would be because I gave a bad example on my part. In my actual version - in the class I have instantiated an XML object containing the twitter feed. So inside the drop RSS function where it assigns the string value what I did in my actual code was grab something like:
feed[current]
If you pass in a string that starts with an ‘@’ my rule says - dismiss this and recalls the function over again after incrementing the ‘current’ variable. If you pass in the string externally this situation will create an infinite loop.
Does that make sense?
joshspoon Says:
8:44 pmMar 18I did change mine to reflect what you talked about.
The only problem is I get a null before my string that the function makes
here is the code:
private function dropRSS():void {
//var cur:String = “Hey @sunnythaper, @shalerjump, @jamesarcher! Check this out: http://tinyurl.com/377owu”
var cur:String = _statusText;
if (cur.substr(0,1) == “@”) { // Skip response messages as they do not always provide enough context to be stand alone statements.
trace(”stall”);
_current++;
dropRSS();
} else {
cur = cur+” “; // Append a space at the end so RegEx catches trailing expressions
var twitterUser:RegExp = /(\s@+\w*(\s|,|!|\.|\n))/; // ”
var url:RegExp = /[^"|^>](http:\/\/+[\S]*)/;
while(twitterUser.exec (cur) != null) {
cur = cur.replace(twitterUser, pointToUser);
}
while(url.exec (cur) != null) {
cur = cur.replace(url, setUrl);
}
cur = cur.replace(/null/,”");
output.htmlText += cur + “\n”;
_current++;
}
}
Jim Jeffers Says:
4:37 pmMar 19Hey Josh,
Check out my code in the actual source for the feed reader I built:
RSS Dropper
joshspoon Says:
11:44 amMar 20http://donttrustthisguy.com/rssdropper.zip
is a 404.
joshspoon Says:
9:02 pmMar 20thanks. I didn’t notice for some reason this was is displaying one at a time and was on a timer. That’s why it didn’t work the way I wanted it.
I’m needing it to loop thur an array of objects and parse each one with their respective links. So I really don’t know RegEx to change what you have and I don’t understand you if statement for the @. So I guess I’ll just keep the hack I have and strip out the wierd null I get. It works other than that.
Eduard Says:
10:01 amJun 04Hi Jim,
Thank you so much about this post. It was really helpful to understand the use of regular expressions in AS3, plus you hinted me to a wonderful OS X app for previewing RegExps!
About the optimization of your loop, it might be solved just by adding the Global flag in your regular expression at the very end: /g For instance, in your example, var url:RegExp = /[^"|^>](http:\/\/+[\S]*)/g;
This will automatically “do the loop” for you and replace all instances at once.
All the best,
Eduard