2010-11-17 6 views
3

J'essaye d'analyser une chaîne que je reçois d'un hashtag, et jusqu'ici il ressemble à une regex pourrait être le chemin le plus propre aller. Le modèle, avec une explication, est la suivante:Regex (ou autre suggestion) pour analyser un hashtag

#p3     -> p = 3 
#h4     ->   h = [ 4 ] 
#h4,h6    ->   h = [ 4, 6 ] 
#p3,h4,h6   -> p = 3, h = [ 4, 6 ] 
#h4,h6,p3   -> p = 3, h = [ 4, 6 ] 
#h4s2,6,10   ->   h = [ 4 ], s = { "4": [ 2, 6, 10 ] } 
#h4s2,6,10,h6s5  ->   h = [ 4, 6 ], s = { "4": [ 2, 6, 10 ] , "6": [ 5 ] } 
#p20h4s2,6,10,h6s5,1 -> p = 20, h = [ 4, 6 ], s = { "4": [ 2, 6, 10 ] , "6": [ 5, 1 ] } 

Comme je l'ai dit, je pense que regex pourrait être mon meilleur pari mais c'est aussi un point faible pour quoi que ce soit complexe.

Si vous avez d'autres suggestions/solutions, alors je les souhaite la bienvenue. Je pourrais le faire en utilisant if/else avec beaucoup de indexOf et splits et ainsi de suite ... mais je suis certain qu'il doit y avoir une meilleure façon que cela.

Mise à jour: La sortie sur la gauche est considérée comme une explication. Bien que ce soit le résultat final souhaité, une solution regex ne doit pas résoudre le problème complet, mais peut-être me faire partie du chemin. Aussi, pour réitérer, je travaille en Javascript.

+0

Y a-t-il un motif régulier que vous pourriez poster? Comme une généralisation du modèle? – jjnguy

+4

@jjnguy: Au son de cela, s'il pouvait le faire, il n'aurait pas besoin de poser la question. – Welbog

+0

@Welbog, j'espérais qu'il répondrait à la question pour lui-même. – jjnguy

Répondre

2

Voici un code pour le faire.

var p, h = [], s = {}; 

var re = /[ph][0-9]+|s[0-9,]*[0-9]/g; 
var a; 
while ((a = re.exec(myhashtag)) !== null) { 
    var first = a[0].substring(0, 1); 
    var rest = a[0].substring(1); 
    if (first == 'p') 
     p = parseInt(rest); 
    else if (first == 'h') 
     h.push(parseInt(rest)); 
    else { 
     a = rest.split(','); 
     for (var i = 0; i < a.length; i++) 
      a[i] = parseInt(a[i]); 
     s[h[h.length - 1]] = a; 
    } 
} 

Il utilise l'expression régulière seulement pour trouver toutes les pièces du hashtag qui ressemblent à p3 ou h4 ou s3,4,5. Le reste est juste du JavaScript courant.

Ce code est très lax. Si le hashtag contient des ordures qui ne peuvent pas être analysées, comme #p3_banana_*q4, ce code l'ignore simplement. Il serait probablement préférable d'écrire un code plus strict qui génère une erreur si le hashtag contient de telles absurdités.

+1

Cela m'a rappelé cours de chimie. 'Ar # 1s22s22p63s23p6' ... –

+0

C'est exactement ce que je pensais. – jjnguy

+0

Merci. Je n'ai pas fait tous les cas de test mais ça marche tellement loin ... et c'est beaucoup plus élégant que ce que j'avais auparavant. – donohoe

0

Les expressions régulières servent à déterminer si un motif donné est présent et éventuellement à agir (remplacement, suppression, etc.). Vous voulez faire plus que cela; vous voulez déterminer si un modèle est présent, puis effectuez une sorte d'analyse basée sur cela. Si ce qu'il était moi, j'exécuterait comme suit (pseudo-code ci-dessous):

 
if(string_begins_with('#')) { 
    if(string_contains('p')) { 
     // get numbers following using some "CSV-to-array" function 
    } 

    if(string_contains('h') { 
     foreach('h') { 
      // check for 's' following, do csv-to-array thing 
     } 
    } 
} 

EDIT: si vous voulez vraiment aller dans cette voie, vous allez devoir utiliser lookaheads. En supposant que le p est fixé au début:

/ 
^\# 
(p[\d,]+)? # find the 'p' 
(   # beginning of 'find the "h"' code 
    h([[0-9],]) # find the 'h' 
    (?=   # beginning of lookahead for 's' 
     (s([[0-9],])+)? # code for s, including a final ? since it may not 
         # be there at all. I'm not sure if this part will work. 
    )   # end of lookahead 
)+   # end of code for 'h', + since you may have more than one 'h' 
/

Ce besoin probablement un peu de travail, mais il est un bon début.

+0

Je suis allé dans cette direction, et c'est peut-être ma seule option. J'espère que regex peut le décomposer au moins en partie. Side Note: J'utilise Javascript, pas PHP – donohoe

5

Vous pouvez probablement utiliser une seule expression pour déterminer si une ligne particulière est valide ou non, mais si vous essayez de construire une structure basée sur les chaînes d'entrée, vous devriez opter pour une tokenisation/analyse en deux étapes. régime puisque cela va simplifier les choses. En apparence, vous avez trois types de jetons: p, h et s. Chaque jeton est une lettre suivie d'un nombre (suivi de plusieurs chiffres dans le cas de s). Donc, je commencerais par un tokenizer, conçu pour convertir la chaîne en une séquence de jetons abstraits. Chaque jeton peut être mis en correspondance à l'aide d'une expression régulière.

Prenons cette chaîne: #p20h4s2,6,10,h6s5,1. Bien qu'il reste encore une entrée, vous allez créer une séquence de jetons basée sur l'entrée restante.Le premier jeton est un p, avec la valeur 20. Ensuite, vous avez un h avec la valeur 4. Puis un s avec la valeur [2,6,10], et ainsi de suite. Pour déterminer quel jeton est lequel, utilisez une expression régulière très simple. L'expression p pourrait être p\d+. h pourrait être h\d+. s ressemble à ce serait s(\d+)(,\d+)*.

Le résultat de votre étape de création de jetons est une séquence d'objets de ce type: { p(20), h(4), s(2,6,10), h(6), s(5,1) }. À ce stade, vous pouvez décider que s(2,6,10) fait partie de h(4) et construire votre structure sans vous soucier de la représentation sous forme de chaîne de la structure. Maintenant, en ce qui concerne l'implémentation en JavaScript, ce ne serait pas trop difficile. La séquence de jetons peut être un tableau, et vous pouvez trouver des jetons en utilisant les blocs if/else et les expressions régulières ci-dessus. L'important est de séparer la partie où vous utilisez la représentation de chaîne (tokenization) et la partie où vous utilisez une représentation abstraite (analyse). Cela rend les choses conceptuellement beaucoup plus simples. Il est également plus facile d'ajouter de nouveaux types de jetons si vous en avez besoin plus tard.

Questions connexes