2010-04-17 100 views
26

Me gustaría agregar un cierto número de ceros a la izquierda (digamos hasta 3) a todos los números de una cuerda. Por ejemplo:Uso de expresiones regulares para agregar ceros a la izquierda

de entrada: /2009/5/song 01 of 12

Salida: /2009/0005/song 0001 of 0012

Cuál es la mejor manera de hacer esto con expresiones regulares?

Editar:

Elegí la primera respuesta correcta. Sin embargo, vale la pena dar una lectura a todas las respuestas.

+0

Primero necesita dividir el texto en componentes usando expresiones regulares (palabras/números) y luego use el formato numérico para agregar los ceros a la izquierda. – serg

+0

Gracias serg555. ¿Por qué no publicar esto como una respuesta? – hpique

Respuesta

5

utilizar algo que es compatible con una devolución de llamada para que pueda procesar el partido:

>>> 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' 
+0

Gracias Ignacio. No es posible sin usar devoluciones de llamada? – hpique

+0

Puede ser posible con una expresión regular suficientemente compleja o con múltiples expresiones regulares, pero a menos que las llamadas a funciones sean ridículamente caras, este método será más rápido. –

2

Una muestra:

>>> re.sub("(?<!\d)0*(\d{1,3})(?!\d)","000\\1","/2009/5/song 01 of 3") 
'/2009/0005/song 0001 of 0003' 

Nota:

  • Sólo funciona para los números 1 - 9 por ahora
  • No está bien probar aún

lo que pueda' Pienso en una sola expresión regular sin usar devoluciones de llamada por ahora * (puede haber una forma de hacerlo).

Aquí hay dos expresiones regulares para procesar esa:

>>> 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' 
+0

No funciona para 011, por ejemplo. – kovpas

+0

@kovpas, sí, bajo pensamiento. Eso es un poco difícil sin usar devoluciones de llamadas, porque el llenado 0 es de longitud variable. – YOU

+0

Gracias por la rápida respuesta, S.Mark. Cambió el ejemplo para desafiar su solución. – hpique

1

Otro enfoque:

>>> 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' 
>>> 

O bien:

>>> 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' 
26

En Perl:

s/([0-9]+)/sprintf('%04d',$1)/ge; 
+2

+ 1 Esa es una expresión regular magníficamente simple y se ajusta a la factura. – dawg

+8

Me hace querer aprender Pearl después de compararlo con mi implementación de Java. – hpique

1

Si su aplicación expresión regular no soporta mirada detrás y/o de preanálisis afirmaciones, también se puede utilizar esta expresión regular:

(^|\D)\d{1,3}(\D|$) 

y reemplazar el partido con $1 + padLeft($2, 4, "0") + $3 donde $1 es el partido del primer grupo y padLeft(str, length, padding) es una función que prefija str con padding hasta la longitud length es reac hed.

0

Aquí hay una solución de Perl sin devolución de llamada ni recursión. Utiliza la extensión Perl regex de la ejecución del código en lugar de la sustitución directa (el modificador e), pero esto se extiende fácilmente a otros lenguajes que carecen de esa construcción.

#!/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 

Salida:

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 
1

<warning> Esto supone un interés académico, por supuesto, usted debe utilizar devoluciones de llamada para hacerlo clara y correctamente </warning>

soy capaz de abusar de las expresiones regulares tener dos ceros a la izquierda (sabor .NET):

s = Regex.Replace(s, @".(?=\b\d\b)|(?=\b\d{1,2}\b)", "$&0"); 

No funciona si hay un número al principio de la cadena. Esto funciona haciendo coincidir el ancho 0 antes que un número o el carácter antes de un número, y reemplazándolos por 0.

No tuve suerte expandiéndolo a tres ceros a la izquierda, y ciertamente no más.

1

Usando c#:

string result = Regex.Replace(input, @"\d+", me => 
{ 
    return int.Parse(me.Value).ToString("0000"); 
}); 
0

combinan en Xcode:

targetName=[NSString stringWithFormat:@"%05d",number]; 

Da 0para el número 123

0

Un programa Scala válida para reemplazar todos los grupos de n dígitos a 4. $$ se escapa la línea que termina char $, porque estamos usando StringContext (cadena prefijada por s).

(f/:(1 to 3)){case (res,i) => 
    res.replaceAll(s"""(?<=[^\\d]|^)(\\d$i)(?=[^\\d]|$$)""", "0"*(4-i)+"$1") 
    } 
Cuestiones relacionadas