Detecting IE with JS conditional comments

I just stumbled upon a short yet excellent post on Dean Edwards blog. It shows how to use IE proprietary javascript conditional comments to detect if we’re running on IE in a secure and very short way.

var isMSIE = /*@cc_on!@*/false;

Further down in the post’s comments someone named Lucky propose the use of a variant to check against IE 5.5+ and IE7. javascript:

var ieScript/*@cc_on=@_jscript_version@*/;
if (ieScript) // IE
if (ieScript>=5.5) // IE 5.5 +
if (ieScript==5.7) // IE 7.0 VistaCopy to clipboard

Moreover Dean also shows in one of the comments how to check for the rendering path used by IE (quirks VS strict modes)

var ieStrict = document.compatMode == 'CSS1Compat';Copy to clipboard

While is not very wise to abuse the sniffing of browsers vendors it’s also true that sometimes it’s required to split the code path in order to support the incompatibilities among browser vendors and versions.

Commenting regular expressions in Javascript

I’ve been working a lot lately with regular expressions in Javascript. Being a really powerful tool it’s quite easy to get shoot on your own feet if you are not careful.

After pushing the Javascript built in regular expression engine to its limits I found it lacking some modern features available in most recent versions of regex engines used in many languages like .Net, C++ Boost, Perl, Ruby or PHP. The feature I miss the most is the ability to use look behind assertions, with JS just supporting look ahead ones. Another feature I miss are named groups and then one very useful new feature is the /x modifier (also known as ignore whitespace) which allows regular expression literals to span over multiple lines, ignoring white space, new lines and embedded comments!

See the following example regex to match an url:

/\b(https?|ftp):\/\/([-A-Z0-9.]+)(\/[-A-Z0-9+&@#/%=~_|!:,.;]*)?(\?[-A-Z0-9+&@#/%=~_|!:,.;]*)?/i

Writting it is not difficult but modifiing it or even understanding it becomes an issue. Using the Perl /x modifier it would look like this:

m/\b                              # match at word break
  (https?|ftp)://                 # protocol: http, https or ftp
  ([-A-Z0-9.]+)                   # domain
  (/[-A-Z0-9+&@#/%=~_|!:,.;]*)?   # file path - optional
  (\?[-A-Z0-9+&@#/%=~_|!:,.;]*)?  # query string - optional
/ix;

Much easier to understand, isn’t it? At least I really think so. To imitate this behaviour in Javascript I’ve written this simple function which just concatenates the regular expressions passed as arguments and returns a new one. This allows to break a complex regex into smaller pieces and comment them.

function xRegExp() {
    var cur, re;
    var arr = [];
    var n = arguments.length;

    // check if the last argument contains the regexp modifiers
    if (/^[gmi]+$/|>.test(arguments[n-1]))
        n--;

    // go thru all the passed regexes and concatenate them
    for (var i=0; i<n; i++) {
        if (typeof arguments[i] === 'string') {
            arr.push( arguments[i] );
        } else {
            // when we cast a regexp object to a string
            // the / delims and modifiers are included
            cur = String(arguments[i]);
            arr.push( cur.substring(cur.indexOf('/')+1, cur.lastIndexOf('/')) );
        }
    }

    // create a new empty regexp
    re = new RegExp();
    // compile the concatenated regex to speed it up
    re.compile( arr.join(''), arguments[n] );
    return re;
}

Please note that the same thing can be done by concatenating strings manually, however regexes syntax is terse enough without having to double escape all the tokens. That’s why I preffer to write them out in their literal form (between slashes) instead of using quotes.

Using the given function the above example would look like this. Note that you can use the regexp literal notation or just pass a simple string. The last argument can optionally pass the modifiers for the regular expression.

var re = new xRegExp(
    /\b/,                                 //match at word break
    '(https?|ftp)://',                    //protocol: http, https and ftp
    '([-A-Z0-9.]+)',                      //domain
    '(/[-A-Z0-9+&@#/%=~_|!:,.;]*)?',      //file path (optional)
    /(\?[-A-Z0-9+&@#/%=~_|!:,.;]*)?/,     //query string (optional)
    'i'                                   //Modifiers: case-insensitive
);

Some brief notes on TextAreaPlus

Been a quite long time since the last update. I’m a bit ashamed for not keeping the blog updated regularly but I must confess that I’ve been expending my time on other affairs more important to me.

Anyways, in this weeks I’ve been working again on TextAreaPlus, actually I’ve been busy making a full rewrite of the lexing scanner and optimizing the implementation to the limits of my knowledge. The algorithm used is described in the project wiki.

Today I was re-installing the PC at work since it broke havoc yesterday. After finishing the installation of almost all softwares I decided to have a look for a notepad replacement which was more feature packed than Scite and a bit faster than Notepad++ to perform some minor editing of config files mainly. In the search I found a couple of new editors which I didn’t knew about but which seem to be gaining momentum. Both seem to be based on a successful Mac text editor called TextMate, which I have heard about from Ruby-on-Rails evangelists but given my allergic reactions to anything mac related lately I didn’t check before. Today, trying those two new editors I got interested in TextMate and I’ve been learning about it in the last hour.

So long history short, I thought I had invented the sliced bread with my implementation and design ideas for TextAreaPlus but it turns out that Allan Oddgaard, the TextMate developer, already implemented it in a very similar way a couple of years ago. My feelings are a bit conflictive right now, in one way I feel sad because I just reinvented the wheel but in the other I feel reassured to have come up with a solution which turns out to be proved and successful.

I’ve written a couple hundred words with a couple of links in this post using a lame browser textarea, in moments like this I wish I had already a production ready version of TextAreaPlus. Lets hope I don’t keep wishing for it too long.

Comprobar un NIF, NIE o CIF

Después de postear un simple código para comprobar un NIF, me he mirado un poco más el tema y para mi sorpresa no hay mucha información sobre esto.

Así que aquí presento una pequeña función para comprobar si el formato de un NIF, NIE o CIF es válido.

<?php
function checkIdentidadFiscal( $str )
{
    //normalizamos el formato
    $str = preg_replace( '/[^0-9A-Z]/i', '', $str );

    // El formato es de un NIF o un NIE
    if (preg_match('/X?[0-9]{8}[A-Z]/i', $str))
    {
          //para no duplicar código, eliminamos la X en el caso de que sea un NIE
          $str = preg_replace('/^X/i', '', $str);

          //calculamos que letra corresponde al número del DNI o NIE
          $stack = 'TRWAGMYFPDXBNJZSQVHLCKE';
          $pos = substr($str, 0, 8) % 23;
          if (strtoupper( substr($str, 8, 1) ) == substr($stack, $pos, 1) )
              return true;
    }
    // El formato es el de un CIF
    else if (preg_match('/[A-HK-NPQS][0-9]{7}[A-J0-9]/i', $str)) //CIF
    {
          //sumar los digitos en posiciones pares
          $sum = 0;
          for ($i=2; $i<strlen($str)-1; $i+=2) {
              $sum += substr($str, $i, 1);
          }

          //Multiplicar los digitos en posiciones impares por 2 y sumar los digitos del resultado
          for ($i=1; $i<strlen($str)-1; $i+=2) {
              $t = substr($str, $i, 1) * 2;
              //agrega la suma de los digitos del resultado de la multiplicación
              $sum += ($t>9)?($t-9):$t;
          }

          //Restamos el último digito de la suma actual a 10 para obtener el control
          $control = 10 - ($sum % 10);

          //El control puede ser un número o una letra
          if ( substr($str, 8, 1) == $control ||
               strtoupper(substr($str, 8, 1)) == substr('JABCDEFGHI', $control, 1 ))
              return true;
          }

          return false;
    }
}

El algoritmo para comprobar el CIF lo he sacado de aquí.