Home & blog  /  2011  /  Jun  /

Understanding multi-line mode for JS REGEX

posted: 30 Jun '11 21:37 tags: REGEXP, Javascript, look-behind, simulation

I wanted to do a post on regular expressions' multi-line mode, since from looking around the net there appears to be a common misconception about what this does.

That's kind of understandable; you might expect something called multi-line mode to enable your REGEX pattern to match within strings that contain line breaks.

But that happens anyway, with or without multi-line mode turned on. See:

1var myStr = "This is a \n multi-line \n\ string";

2words = myStr.match(/\w+/g);

3if (words) alert(words.join('\n'));

That will find and alert out all the words (notice I pass the global flag, as I want all the words, not just the first) - even though I ran the REGEX on a multi-line string and didn't stipulate multi-line mode.

No; what multi-line mode is about is changing the behaviour of the ^ and $ anchors.

Normally, these match the start and end of the string, respectively. In multi-line mode, though - which is turned on by passing an 'm' after the final forward slash of your pattern - their meanings are extended to also match the moments before ($) and after (^) a line-break.

So imagine I have a pattern which tries to match as many characters as it can, in succession, of any kind (that's what the [\s\S] does - matches all characters, including spacial characters). Let's try it without multi-line mode first:

1var myStr = "This is a \n multi-line \n\ string";

2alert(myStr.match(/^[\s\S]+$/g));

There, I simply get back the whole string. The ^ matches the start of the string, then matches all the characters in succession, then finally hits the end of the string ($). But in multi-line mode:

1var myStr = "This is a \n multi-line \n\ string";

2alert(myStr.match(/^[\s\S]+$/gm));

This time we get back an array of 3 items - one for each word or sequence of words delimited by the line breaks.

So what's happening there is the ^ matches the start of the string, it matches "this is a " but then finds the starting edge of a line-break. In multi-line mode, the $ matches this, so that's the end of a match. And since I'm in global mode, matching continues after the line-break.

So in conclusion, not the most indicative of names, but it can be useful. Not often, mind...

post a comment

On-the-fly conversion of Flash to image for iOS

posted: 08 Jun '11 14:34 tags: Flash, Apple, PHP, screen, iPad

In this brave new world of smart phones and tablet PCs, the firm I work for is focusing a lot of energy these days on how to roll out its historical content onto these devices.

The problem is, over the years, we've made a lot of Flash banners. And iOS, the OS behind iPhone and iPad, doesn't support Flash.

I was charged with coming up with a solution. What's a quick way of generating static image equivalents of thousands of Flash banners?

I came up with a solution involving JS and PHP. The concept is this: as users browse our content on Flash-supporting PCs, a secret PHP script is loaded in a hidden iFrame that takes a screenshot of the page (yes, it can do this).

Data regarding the banner's position and dimensions is passed to the script by Javascript in the query string.

Works a treat. Though users don't realise it, they're helping us create a cache of images that are alternatives to Flash banners.

We did hit one snag, though. As I said, JS passes PHP the coordinates of the banner – but of course these coordinates are relative to the viewport – not the window, but PHP's screenshot is of the window, i.e. toolbars and all.

There is no way in PHP to capture the contents of a window – only the window, complete with toolbars and other periphirals.

IE actually provided a solution to this problem. It defines window.screenLeft and window.screenTop – respectively, the left and top position of the viewport relative to the window. Hurrah! But no… Firefox doesn't define these properties. Other browsers do, but give them other meaning, so no dice.

But there is a solution. A very hacky, almost whorish solution, but it works. I'll write a separate blog post in the next few days detailing the technical steps of this conundrum, in case it helps anyone else.

post a comment
older posts >