У меня есть строка "The dog has 12.345 bones". Я хочу сопоставить 12.345 и заменить его . на XYZ так, чтобы строка стала "The dog has 12XYZ345 bones". Число может быть любым допустимым числом, состоящим из тысяч точек, поэтому 1, 456, 1.000 или 34.234.233. Например, 100.00 недействителен. Как бы я это сделал?

Для интернет-адресов я использовал

address_pattern = r"(www).([A-Za-z0-9]*)\.(de|com|org)"
re.sub(address_pattern, r"\XYZ\2XYZ\3", text)

Но проблема в том, что числа могут быть сколь угодно длинными, у меня нет точного количества групп для замены.

4
MarcelB 25 Окт 2021 в 01:03
. используется как разделитель тысяч? Если у вас есть 1 или 456, они станут 1XYZ и 456XYZ?
 – 
dawg
25 Окт 2021 в 01:12
Нет, они останутся такими же, потому что у них нет тысяч точек.
 – 
MarcelB
25 Окт 2021 в 02:04

2 ответа

Лучший ответ

Использовать

import re
regex = r"(?<!\S)\d{1,3}(?:\.\d{3})*(?!\S)"
test_str = "The dog has 12.345 bones"
print(re.sub(regex, lambda m: m.group().replace('.','XYZ'), test_str))

Результаты : The dog has 12XYZ345 bones

См Python доказательства. Точки внутри совпадающих чисел заменяются на lambda m: m.group().replace('.','XYZ').

ОБЪЯСНЕНИЕ К ВЫРАЖЕНИЮ

--------------------------------------------------------------------------------
  (?<!                     look behind to see if there is not:
--------------------------------------------------------------------------------
    \S                       non-whitespace (all but \n, \r, \t, \f,
                             and " ")
--------------------------------------------------------------------------------
  )                        end of look-behind
--------------------------------------------------------------------------------
  \d{1,3}                  digits (0-9) (between 1 and 3 times
                           (matching the most amount possible))
--------------------------------------------------------------------------------
  (?:                      group, but do not capture (0 or more times
                           (matching the most amount possible)):
--------------------------------------------------------------------------------
    \.                       '.'
--------------------------------------------------------------------------------
    \d{3}                    digits (0-9) (3 times)
--------------------------------------------------------------------------------
  )*                       end of grouping
--------------------------------------------------------------------------------
  (?!                      look ahead to see if there is not:
--------------------------------------------------------------------------------
    \S                       non-whitespace (all but \n, \r, \t, \f,
                             and " ")
--------------------------------------------------------------------------------
  )                        end of look-ahead
1
Ryszard Czech 25 Окт 2021 в 01:07
1
Выглядит хорошо, спасибо! Я искал лямбда-функцию.
 – 
MarcelB
25 Окт 2021 в 02:05
1
Да, в качестве замены re.sub можно использовать как лямбда-методы, так и отдельные методы.
 – 
Ryszard Czech
25 Окт 2021 в 02:12

Если вы действительно хотите заменить . только при использовании в качестве разделителя тысяч, вы можете сделать:

(?:<\D|^)\d{1,3}(?:\.\d{3})+(?=[^\d.]|$)

Демо

Демонстрация Python:

import re

txt='''
1
456
1.000
34.234.233
100.00
'''

print(
    re.sub(r'(?:<\D|^)\d{1,3}(?:\.\d{3})+(?=[^\d.]|$)', 
        lambda m: m.group(0).replace('.', 'XYZ'), 
        txt, flags=re.M)
)

Печать:

1
456
1XYZ000
34XYZ234XYZ233
100.00
0
dawg 25 Окт 2021 в 03:30