2010-05-22 6 views
7

Considérez ce javascript:Javascript Regex pour convertir la notation de points à la notation de support

var values = { 
    name: "Joe Smith", 
    location: { 
     city: "Los Angeles", 
     state: "California" 
    } 
} 

var string = "{name} is currently in {location.city}, {location.state}"; 

var out = string.replace(/{([\w\.]+)}/g, function(wholematch,firstmatch) { 
    return typeof values[firstmatch] !== 'undefined' ? 
     values[firstmatch] : wholematch; 
}); 

Cette volonté génèrerait les éléments suivants:

Joe Smith is currently in {location.city}, {location.state} 

Mais je veux génèrerait les éléments suivants:

Joe Smith is currently in Los Angeles, California 

Je cherche un bon moyen de convertir plusieurs niveaux de notation par points trouvés entre accolades dans la chaîne en plusieurs les paramètres à utiliser avec la notation de support, comme ceci:

values[first][second][third][etc] 

Essentiellement, pour cet exemple, je suis en train de comprendre quelle chaîne regex et la fonction que je devrais finir avec l'équivalent de:

out = values[name] + " is currently in " + values["location"]["city"] + 
    values["location"]["state"]; 

REMARQUE: Je voudrais faire cela sans utiliser eval().

+0

juste trouvé une faute. Renommé 'var joe' en' var values' – Tauren

+0

Une autre question similaire a une solution alternative par @ J-P aux réponses ici. Il semble assez élégant: http://stackoverflow.com/questions/3344392/dynamic-deep-selection-for-a-javascript-object/3344487#3344487 – Tauren

Répondre

10

l'aide d'une fonction d'aide pour accéder itérativement les propriétés:

function getNestedValue(obj, prop) { 
    var value, props = prop.split('.'); // split property names 

    for (var i = 0; i < props.length; i++) { 
    if (typeof obj != "undefined") { 
     obj = obj[props[i]]; // go next level 
    } 
    } 
    return obj; 
} 

var string = "{name} is currently in {location.city}, {location.state}"; 

var out = string.replace(/{([^}]+)}/g, function(wholematch,firstmatch) { 
    var value = getNestedValue(joe, firstmatch); 
    return typeof value !== 'undefined' ? value : wholematch; 
}); 
// "Joe Smith is currently in Los Angeles, California" 

Essayez l'exemple ci-dessus here.

Modifier: Quelque chose légèrement élégant, en utilisant la méthode Array.prototype.reduce, une partie de la nouvelle ECMAScript 5 Standard Edition:

function replace(str, obj) { 
    return str.replace(/{([^}]+)}/g, function(wholematch,firstmatch) { 
    var value = firstmatch.split('.').reduce(function (a, b) { 
     return a[b]; 
    }, obj); 
    return typeof value !== 'undefined' ? value : wholematch; 
    }); 
} 

replace("{name} is currently in {location.city}, {location.state}", values); 
// "Joe Smith is currently in Los Angeles, California" 

Essayez le nouvel exemple here.

+0

@CMS: sympa, ça marche! Cependant, il ne semble pas aussi élégant qu'une solution basée sur regex, et j'aimerais croire qu'il existe une façon regex de le faire. Là encore, peut-être que ce serait une perte de temps de rechercher une solution regex. – Tauren

+0

@CMS: votre regex n'autorise-t-elle rien entre les accolades? si je veux limiter les valeurs aux noms de variables javascript valides '[a-zA-Z0-9 _ \.]', ne serait-il pas préférable d'utiliser '/ {([\ w \.] +)}/g'?En fait, cela permettrait une période au début, ce qui n'est pas autorisé, mais c'est proche. Ah oui, je pense que je dois aussi inclure $. – Tauren

+0

@Tauren, c'est juste un peu permissif, je m'en foutais trop, car quand on accède aux propriétés avec la notation de parenthèse (ou qu'on utilise des chaînes dans un littéral d'objet), il n'y a pas de restrictions, ie \ u0009 "]' ... – CMS

0

Je ne suis pas sûr de savoir comment intégrer cela dans Javascript, mais voici un extrait Java qui utilise regex pour faire la transformation dont vous avez besoin:

String[] tests = { 
     "{name}", 
     "{location.city}", 
     "{location.state.zip.bleh}", 
    }; 
    for (String test : tests) { 
     System.out.println(test.replaceAll("\\{?(\\w+).?", "[$1]")); 
    } 

Cette impression:

[name] 
[location][city] 
[location][state][zip][bleh] 

Essentiellement, il remplace toutes les occurrences de \{?(\w+).? par [$1].

+0

hmm, intéressant. Cependant, même si je travaillais dans JS, je pensais que je finirais avec une corde que j'aurais besoin d'évaluer, ce que je voudrais éviter. – Tauren

0

Vous pouvez regarder le sujet Error-free deep property access? posté sur comp.lang.javascript - cela présente plusieurs approches pour faire ce que vous voulez.

regexp, tout ce que vous avez besoin est /{.*?}/g

Questions connexes