Je voudrais ajouter un certain nombre de zéros non significatifs (disons jusqu'à 3) à tous les nombres d'une chaîne. Par exemple:
Entrée: /2009/5/song 01 of 12
Sortie: /2009/0005/song 0001 of 0012
Quelle est la meilleure façon de faire cela avec des expressions régulières?
Modifier:
J'ai choisi la première réponse correcte. Cependant, toutes les réponses valent la peine d'être lues.
Utilisez quelque chose qui prend en charge un rappel afin de pouvoir traiter la correspondance:
>>> r=re.compile(r'(?:^|(?<=[^0-9]))([0-9]{1,3})(?=$|[^0-9])')
>>> r.sub(lambda x: '%04d' % (int(x.group(1)),), 'dfbg345gf345', sys.maxint)
'dfbg0345gf0345'
>>> r.sub(lambda x: '%04d' % (int(x.group(1)),), '1x11x111x', sys.maxint)
'0001x0011x0111x'
>>> r.sub(lambda x: '%04d' % (int(x.group(1)),), 'x1x11x111x', sys.maxint)
'x0001x0011x0111x'
En Perl:
s/([0-9]+)/sprintf('%04d',$1)/ge;
Un échantillon:
>>> re.sub("(?<!\d)0*(\d{1,3})(?!\d)","000\\1","/2009/5/song 01 of 3")
'/2009/0005/song 0001 of 0003'
Remarque:
Je ne peux pas penser à une seule expression régulière sans utiliser les rappels pour l'instant * (il pourrait y avoir un moyen de le faire).
Voici deux expressions régulières pour traiter cela:
>>> x = "1/2009/5/song 01 of 3 10 100 010 120 1200 abcd"
>>>
>>> x = re.sub("(?<!\d)0*(\d{1,3})(?!\d)","000\\1",x)
#'0001/2009/0005/song 0001 of 0003 00010 000100 00010 000120 1200 abcd'
>>>
>>> re.sub("0+(\d{4})(?!\d)","\\1",x) #strip extra leading zeroes
'0001/2009/0005/song 0001 of 0003 0010 0100 0010 0120 1200 abcd'
Utiliser c#
:
string result = Regex.Replace(input, @"\d+", me =>
{
return int.Parse(me.Value).ToString("0000");
});
Si votre implémentation d'expression régulière ne prend pas en charge les assertions d'anticipation et/ou d'anticipation, vous pouvez également utiliser cette expression régulière:
(^|\D)\d{1,3}(\D|$)
Et remplacez la correspondance par $1 + padLeft($2, 4, "0") + $3
où $1
est la correspondance du premier groupe et padLeft(str, length, padding)
est une fonction qui préfixe str
avec padding
jusqu'à atteindre la longueur length
.
<warning>
Ceci suppose un intérêt académique, bien sûr, vous devez utiliser des rappels pour le faire clairement et correctement </warning>
Je peux abuser des expressions régulières pour avoir deux zéros non significatifs (saveur .NET):
s = Regex.Replace(s, @".(?=\b\d\b)|(?=\b\d{1,2}\b)", "$&0");
Cela ne fonctionne pas s'il y a un nombre au début de la chaîne. Cela fonctionne en faisant correspondre la largeur à 0 avant un nombre ou le caractère avant un nombre et en les remplaçant par 0.
Je n’ai pas eu la chance de l’étendre à trois zéros en tête, et certainement pas plus.
Une autre approche:
>>> x
'/2009/5/song 01 of 12'
>>> ''.join([i.isdigit() and i.zfill(4) or i for i in re.split("(?<!\d)(\d+)(?!\d)",x)])
'/2009/0005/song 0001 of 0012'
>>>
Ou:
>>> x
'/2009/5/song 01 of 12'
>>> r=re.split("(?<!\d)(\d+)(?!\d)",x)
>>> ''.join(a+b.zfill(4) for a,b in Zip(r[::2],r[1::2]))
'/2009/0005/song 0001 of 0012'
Un programme Scala valide permettant de remplacer tous les groupes de n chiffres par 4. $$
échappe à la fin de la ligne car $
, car nous utilisons StringContext (chaîne préfixée par s).
(f/:(1 to 3)){case (res,i) =>
res.replaceAll(s"""(?<=[^\\d]|^)(\\d$i)(?=[^\\d]|$$)""", "0"*(4-i)+"$1")
}
Voici une solution Perl sans rappel ni récursivité. Il utilise l'extension d'exécution du code Perl regex à la place de la substitution directe (le commutateur e
), mais il est très facilement étendu à d'autres langages dépourvus de cette construction.
#!/usr/bin/Perl
while (<DATA>) {
chomp;
print "string:\t\t\t$_\n";
# uncomment if you care about 0000000 case:
# s/(^|[^\d])0+([\d])/\1\2/g;
# print "now no leading zeros:\t$_\n";
s/(^|[^\d]{1,3})([\d]{1,3})($|[^\d]{1,3})/sprintf "%s%04i%s",$1,$i=$2,$3/ge;
print "up to 3 leading zeros:\t$_\n";
}
print "\n";
__DATA__
/2009/5/song 01 of 12
/2010/10/song 50 of 99
/99/0/song 1 of 1000
1
01
001
0001
/001/
"02"
0000000000
Sortie:
string: /2009/5/song 01 of 12
up to 3 leading zeros: /2009/0005/song 0001 of 0012
string: /2010/10/song 50 of 99
up to 3 leading zeros: /2010/0010/song 0050 of 0099
string: /99/0/song 1 of 1000
up to 3 leading zeros: /0099/0/song 0001 of 1000
string: 1
up to 3 leading zeros: 0001
string: 01
up to 3 leading zeros: 0001
string: 001
up to 3 leading zeros: 0001
string: 0001
up to 3 leading zeros: 0001
string: /001/
up to 3 leading zeros: /0001/
string: "02"
up to 3 leading zeros: "0002"
string: 0000000000
up to 3 leading zeros: 0000000000
Combiné dans Xcode:
targetName=[NSString stringWithFormat:@"%05d",number];
Donne 00123 pour le numéro 123