mo.notono.us

Wednesday, June 17, 2009

More complicated JavaScript string tokenizer – and Twitter Conversations

(I'm not sure when I started using the term tokenizer - "formatter" may be more common...)

I’ve experimented in the past with a C# string.Format() alternative that would allow property names as tokens rather than the numeric index based tokens that string.Format() uses.  Hardly a unique approach, and many others did it better.

Here’s another first-draft ‘tokenizer’, this time in JavaScript:

String.prototype.format = function(tokens) {
///<summary>
///This is an extension method for strings, using string or numeric tokens (e.g. {foo} or {0}) to format the string.
///<summary>
///<param name="tokens">One or more replacement values
///if a single object is passed, expects to match tokens with object property names, 
///if a single string, number or boolean, replaces any and all tokens with the string
///if multiple arguments are passed, replaces numeric tokens with the arguments, in the order passed
///</param>
///<returns>the string with matched tokens replaced</returns>
  var text = this;
  try  {
    switch (arguments.length) {
      case 0: {
        return this;
      };
      case 1: 
      {
        switch (typeof tokens) {
          case "object":
          {
            //loop through all the properties in the object and replace tokens matching the names
            var token;
            for (token in tokens) {
              if (!tokens.hasOwnProperty(token) || typeof tokens[token] === 'function') {
                break;
              }
              //else
              text = text.replace(new RegExp("\\{" + token + "\\}", "gi"), tokens[token])
            }
            return text;
          };
        case "string":
        case "number":
        case "boolean":
          {
            return text.replace(/{[a-z0-9]*}/gi, tokens.toString());
          };
        default:
            return text;
        };
      };
      default:
      {
        //if multiple parameters, assume numeric tokens, where each number matches the argument position
        for (var i = 0; i < arguments.length; i++) {
          text = text.replace(new RegExp("\\{" + i + "\\}", "gi"), arguments[i].toString());
        }
        return text;
      };
    };
  } catch (e) {
    return text;
  }
};

The comment (in VS Intellisense format) is pretty self-explanatory, note that it doesn’t allow any special formatting as String.Format does, nor does it even support escaping {}‘s – in general it is quite crude.

That said, when used within it’s limitations it works - below are a couple of actual usage scenarios, both from my ongoing Twitter Conversations experiment:

var url = "http://search.twitter.com/search.json?q=from:{p1}+to:{p2}+OR+from:{p2}+to:{p1}&since={d1}&until={d2}&rpp=50".format({ 
  p1: $("#p1").attr("value"), 
  p2: $("#p2").attr("value"),
  d1: $("#d1alt").attr("value"), 
  d2: $("#d2alt").attr("value")
});

and

$.getJSON(url + "&callback=?", function(data) {
  $.each(data.results, function(i, result) {
    content = ' \
<p> \
	<a href="http://twitter.com/{from_user}"><img src="{profile_image_url}" />{from_user}</a> \
	(<a href="http://twitter.com/{from_user}/statuses/{id}">{created_at}</a>): \
	{text} \
</p>'.format(result);

The working Twitter Conversations sample is here, as you can tell it’s really just a wrapper around the Twitter Search API.

Labels: , , ,

1 Comments:

Post a Comment

<< Home