Используя regex для добавления продвижения обнуляет

Я хотел бы добавить, что определенное число продвижения обнуляет (скажите до 3) ко всем числам строки. Например:

Вход: /2009/5/song 01 of 12

Вывод: /2009/0005/song 0001 of 0012

Что лучший способ состоит в том, чтобы сделать это с регулярными выражениями?

Править:

Я выбрал первый корректный ответ. Однако все ответы стоят дать чтение.

27
задан hpique 18 April 2010 в 23:26
поделиться

8 ответов

Используйте что-то, что поддерживает обратный вызов, чтобы вы могли обработать совпадение:

>>> 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
ответ дан 28 November 2019 в 05:26
поделиться

Пример:

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

Примечание:

  • На данный момент он работает только для чисел 1–9
  • Это еще не тест

Я не могу сейчас придумать ни одного регулярного выражения без использования обратных вызовов * (может быть, есть способ сделать это).

Вот два регулярных выражения для их обработки:

>>> 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
ответ дан 28 November 2019 в 05:26
поделиться

На Perl:

s/([0-9]+)/sprintf('%04d',$1)/ge;
29
ответ дан 28 November 2019 в 05:26
поделиться

Вот решение Perl без обратных вызовов и рекурсии. Он действительно использует расширение Perl regex для выполнения кода вместо прямой подстановки (переключатель e ), но его очень легко распространить на другие языки, в которых отсутствует эта конструкция.

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

Вывод:

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
ответ дан 28 November 2019 в 05:26
поделиться

Это предполагает академический интерес, конечно, вы должны использовать обратные вызовы, чтобы делать это четко и правильно

Я могу злоупотреблять регулярными выражениями, чтобы иметь два начальных нуля (вариант .NET):

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

Это не сработает, если в начале строки стоит число. Это работает путем сопоставления ширины 0 перед числом или символа перед числом и замены их на 0.

Мне не удалось расширить его до трех ведущих нулей, и уж тем более не более.

1
ответ дан 28 November 2019 в 05:26
поделиться

Если ваша реализация регулярного выражения не поддерживает утверждения просмотра назад и / или вперед, вы также можете использовать это регулярное выражение:

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

И замените совпадение на $ 1 + padLeft ($ 2, 4, "0") + $ 3 , где $ 1 - это совпадение с первой группой, а padLeft (str, length, padding) - это функция, которая префикс str с заполнением , пока не будет достигнута длина длина .

1
ответ дан 28 November 2019 в 05:26
поделиться

Другой подход:

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

Или:

>>> 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
ответ дан 28 November 2019 в 05:26
поделиться

Использование c # :

string result = Regex.Replace(input, @"\d+", me =>
{
    return int.Parse(me.Value).ToString("0000");
});
1
ответ дан 28 November 2019 в 05:26
поделиться
Другие вопросы по тегам:

Похожие вопросы: