Pregunta Usando expresiones regulares para agregar ceros a la izquierda


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:

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:

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


27
2018-04-17 16:14


origen


Respuestas:


Use algo que admita una devolución de llamada para que pueda procesar la coincidencia:

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

5
2018-04-17 16:32



En Perl:

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

28
2018-04-17 17:06



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:

  • Solo funciona para los números del 1 al 9 por ahora
  • Aún no está bien la prueba

No puedo pensar 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 eso:

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

2
2018-04-17 16:25



Utilizando c#:

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

1
2018-04-23 15:59



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:

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

1
2018-04-17 16:53



Si la implementación de expresiones regulares no es compatible con las afirmaciones de mirar hacia atrás o mirar hacia adelante, también puede usar esta expresión regular:

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

Y reemplace el partido con $1 + padLeft($2, 4, "0") + $3 dónde $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 alcanzado.


1
2018-04-17 17:49



<warning> Esto supone interés académico, por supuesto, debe usar devoluciones de llamada para hacerlo de forma clara y correcta </warning>

Puedo abusar de expresiones regulares para 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 de un número o el carácter antes de un número, y reemplazándolos con 0.

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


1
2018-04-18 09:27



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 e cambiar) pero esto se extiende muy 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

0
2018-04-17 18:23



Combinado en Xcode:

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

Da 00123 para el número 123


0
2017-08-10 05:38



Un programa válido de Scala para reemplazar todos los grupos de n dígitos por 4. $$ escapa de 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")
  }

0
2018-01-23 12:07