2
votes

Comment combiner des expressions régulières pour faire correspondre des chaînes avec et sans délimiteurs?

J'ai des chaînes comme les suivantes mentionnées comme Input qui doivent être traitées et transformées en nom / valeur code> paires comme indiqué ci-dessous:

Entrée: FOO = BAR = BAZ Sortie: name = 'FOO', value = 'BAR = BAZ'

Entrée : FOO = BAR Sortie: name = 'FOO', value = 'BAR'

Entrée: FOO = Sortie : name = 'FOO', value = ''

Entrée: em> = BAR = BAZ Sortie : name = '', value = 'BAR: BAZ'

Entrée: = BAR Sortie: name = '', value = 'BAR'

Entrée: em> FOO Sortie: name = 'FOO', value = ''

Notez que le délimiteur est soit = ou : . Il est également possible de ne pas avoir de délimiteur.

Le code suivant couvre tous les cas mentionnés ci-dessus à l'exception du dernier,

regexp {^\s*(.*?)\s*$} $setting -> name value

pour lequel il renvoie p >

Résultat: name = '', value = ''

au lieu de

Résultat: name = 'FOO', value = ''

Le dernier cas pourrait être couvert par le expression régulière ci-dessous:

regexp {^\s*(.*?)\s*[=:]\s*(.*?)\s*$} $setting -> name value

if {![info exists name]} {
    set name {}
}

if {![info exists value]} {
    set value {}
}

puts "name='$name', value='$value'"

Comment ces expressions régulières pourraient-elles être combinées pour n'avoir qu'une seule expression régulière couvrant tous les cas?


2 commentaires

Une autre suggestion: les tests [info exists] ne sont pas nécessaires, toutes les variables de sous-correspondance seront définies sur une chaîne vide (si elles ne correspondent pas pour une raison quelconque).


Oui, en effet, ils ne sont pas nécessaires lors de l'utilisation de l'expression régulière que vous avez suggérée :)


3 Réponses :


1
votes

Comment ces expressions régulières pourraient-elles être combinées pour n'avoir qu'une seule expression régulière couvrant tous les cas?

La première inclut déjà la seconde :) Mais votre expression régulière plus étendue ne peut pas correspondre à la dernière casse ( FOO ) car elle ne contient pas du tout les caractères de délimitation. Regardez le résultat de la [expression régulière] , qui sera 0.

Considérez ce qui suit:

 ^\s*([^=:]*)\s*[=:]?\s*(.*)\s*$

0 commentaires

2
votes

Je ne vois pas pourquoi vous insistez pour faire cela avec regexp . Lorsque votre expression régulière devient trop compliquée, il est peut-être temps d'utiliser une approche différente. En supposant qu'il n'y ait pas de caractères NUL dans votre chaîne, vous pouvez le faire à la place:

lassign [split [regsub {\s*[:=]\s*} [string trim $setting] \0] \0] name value

Le découpage de chaîne supprime tout espace blanc environnant. Ensuite, le délimiteur et tout espace blanc environnant sont remplacés par un caractère NUL. Enfin le résultat est divisé en deux sur ce caractère NUL et les deux parties sont affectées aux variables de nom et de valeur.

D'après mes mesures, cette méthode est plus de deux fois plus rapide que la variante de l'expression rationnelle.


0 commentaires

1
votes
name='FOO', value='BAR=BAZ'
name='FOO', value='BAR'
name='FOO', value=''
name='', value='BAR=BAZ'
name='', value='BAR'
name='FOO', value=''

0 commentaires