1

I found my self quite often parsing values from the so called Name Value Lists in JavaScript.

I used a self made function which did the job pretty well, however I decided to experiment with the prototype property. It seems to work, however I find the second function "nvlSet" kind of "ugly".

Do you think it is?.. if so, how do you think it can turn into a more "elegant" way to do the job.

if(!String.prototype.nvlGet) {
    String.prototype.nvlGet = function(nme,def){
        return((rem0=new RegExp('(\\b|,)' + nme + '=([^\\b][^,]*)').exec(this)) ? rem0[2] : def);
    }
}
if(!String.prototype.nvlSet) {
    String.prototype.nvlSet = function(nme,val){
        var re0=new RegExp('(\\b' + nme + '=[^\\b][^,]*)');
        if(re0.test(this)) return(this.replace(re0,nme + "=" + val));
        re0.compile('(,' + nme + '=[^\\b][^,]*)');
        return(this.replace(re0,',' + nme + "=" + val));
    }
}

var lst='firstName=John,lastName=Smith,department=Sales';
alert(lst.nvlGet('firstName')); // John
alert(lst.nvlGet('surName','none')); // none
lst=lst.nvlSet('department','Research');
alert(lst.nvlGet('department','unknown')); // Research
alert(lst); // firstName=John,lastName=Smith,department=Research

Also, I would like to avoid the "double assignation" like in here:

lst=lst.nvlSet('department','Research');

To something like this:

lst.nvlSet('department','Research');

However I could not find a way to do it.

Talaveriux
  • 83
  • 1
  • 5

3 Answers3

2

What I would suggest is serializing and deserializing nvls into Objects. A fairly simple example is:

function deserialize(nvl) {
  var re = /(\w+)=(\w+)/g, matches, props = {};
  while (matches = re.exec(nvl)) {
    props[matches[1]] = matches[2];
  }
  return props;
}

function serialize(props) {
  var prop, nvl = [];
  for (prop in props) {
    if (props.hasOwnProperty(prop)) {
      nvl.push(prop + '=' + props[prop]);
    }
  }
  return nvl.join(',');
}

Now your example becomes:

var props = deserialize('firstName=John,lastName=Smith,department=Sales');
alert(props.firstName); // John
alert(props.surName); // undefined
props.department = 'Research';
alert(props.department); // Research
alert(serialize(props)); // firstName=John,lastName=Smith,department=Research
Justin Summerlin
  • 4,938
  • 1
  • 16
  • 10
  • This one looks good and fast, however we have a bunch of Svr sde Scripts that return data in that format (plain text nvl). The data returned has to be parsed in some scenarios many many times per second. So thats why I choose direct regex on the string however this is definitely elegant and will be used in some scenarios. Thanks! – Talaveriux Oct 11 '12 at 05:40
1

Strings are immuatable in javascript. You cannot change the contents of the current string object - ever. That's why all string methods that operate on the string return a new string object. So, your desired structure of:

lst.nvlSet('department','Research');

where you want it to modify the current string object cannot be done.

You could make your own regular object that saves the state and then have methods that get or set that state like this:

function nvl(str) {
    this.data = {};
    if (str) {
        this.data = this.parse(str);
    }
}

nvl.prototype = {
    parse: function(str) {
        var result = {}, pieces;
        var items = str.split(",");
        for (var i = 0; i < items.length; i++) {
            pieces = items[i].split("=");
            result[pieces[0]] = pieces[1];
        }
        return(result);
    },
    get: function(key, defaultVal) {
        var val = this.data[key];
        if (val === undefined) {
            val = defaultVal;
        }
        return(val);
    },
    set: function(key, value) {
        this.data[key] = value;
    },
    serialize: function() {
        var arr = [];
        for (var i in this.data) {
            if (this.data.hasOwnProperty(i)) {
                arr.push(i + "=" + this.data[i]);
            }
        }
        return(arr.join(","));
    }
};

Working example: http://jsfiddle.net/jfriend00/3urJF/

jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • +1, the OP should use a constructor and put the *nvlSet* and *nvlSet* methods on its prototype. – RobG Oct 11 '12 at 00:18
  • I learned something today about JS, you got exactly what i meant with "double assignation" and thanks to your comment I know that is not possible. I will use your complete class for other similar scenarios that do not get executed many times per second. – Talaveriux Oct 11 '12 at 05:47
0

How about this:

//add nvl as a method to String prototype
String.prototype.nvl = function(){

    //new prototype for the dictionary object that gets returned
    var proto = {

        //convert the object literal back into a nvl
        toNvl: function(){

            var str = [];
            for(var i in this){

                if( this.hasOwnProperty(i) ){
                    str.push(i+'='+this[i]);
                }

            }

            //return str.join(',');
            return str.join(',');
        }
    },
    //set the prototype of the object literal to our own
    dict = Object.create(proto);

    //convert the string into an object literal
    keys = this.split(',');

    keys.forEach(function(val, index, arr){
        arr = val.split('=');
        dict[arr[0]] = arr[1];
    });

    return dict;
}


var pop = 'color=blue,num=234'.nvl(); //convert the string to an object

pop.color = 'red'; //access object properties normally.

pop = pop.toNvl(); //convert back to nvl. reassignment is unfortunately necessary
Geuis
  • 41,122
  • 56
  • 157
  • 219