Корпус нечутливий замінити


Відповіді:


217

stringТип не підтримує це. Вам, мабуть, найкраще скористатися методом sub регулярного вираження з опцією re.IGNORECASE

>>> import re
>>> insensitive_hippo = re.compile(re.escape('hippo'), re.IGNORECASE)
>>> insensitive_hippo.sub('giraffe', 'I want a hIPpo for my birthday')
'I want a giraffe for my birthday'

11
Якщо ви робите лише одну заміну або хочете зберегти рядки коду, ефективніше використовувати одну заміну на re.sub та прапор (? I): re.sub ('(? I)' + re .escape ('бегемот'), 'жирафа', 'я хочу гиппо на день народження')
D Coetzee

3
Навіщо повторно створювати лише рядки літер? Дякую.
Олена

8
@Elena, це не потрібно для 'hippo', але було б корисно, якби значення для заміни було передано у функцію, тому це справді більше, ніж хороший приклад, ніж будь-що інше.
Блер Конрад

2
Окрім того, що у re.escapeвас є голка, тут є ще одна пастка, якої не можна уникнути цієї відповіді, зазначається в stackoverflow.com/a/15831118/1709587 : оскільки re.subобробляє послідовності втечі, як зазначено в docs.python.org/library/re.html#re .sub , вам потрібно відмовитися від усіх зворотних косих рядків у вашій заміні рядка або використовувати лямбда.
Марк Амері

84
import re
pattern = re.compile("hello", re.IGNORECASE)
pattern.sub("bye", "hello HeLLo HELLO")
# 'bye bye bye'

17
Або однолінійний: re.sub('hello', 'bye', 'hello HeLLo HELLO', flags=re.IGNORECASE)
Луї Ян

Зауважте, що re.subцей прапор підтримується лише з Python 2.7.
fuenfundachtzig

47

В одному рядку:

import re
re.sub("(?i)hello","bye", "hello HeLLo HELLO") #'bye bye bye'
re.sub("(?i)he\.llo","bye", "he.llo He.LLo HE.LLO") #'bye bye bye'

Або скористайтеся необов'язковим аргументом "прапори":

import re
re.sub("hello", "bye", "hello HeLLo HELLO", flags=re.I) #'bye bye bye'
re.sub("he\.llo", "bye", "he.llo He.LLo HE.LLO", flags=re.I) #'bye bye bye'

14

Продовжуючи відповідь bFloch, ця функція змінить не одне, а всі випадки старого з новим - у випадку нечутливого.

def ireplace(old, new, text):
    idx = 0
    while idx < len(text):
        index_l = text.lower().find(old.lower(), idx)
        if index_l == -1:
            return text
        text = text[:index_l] + new + text[index_l + len(old):]
        idx = index_l + len(new) 
    return text

Дуже добре зроблено. Набагато краще, ніж регекс; він обробляє всілякі символи, тоді як регулярний вираз дуже метушливий щодо нічого не буквено-цифрового. Бажана відповідь IMHO.
fyngyrz

Все, що вам потрібно зробити - це уникнути регулярного вираження: прийнята відповідь набагато коротша і легша для читання, ніж ця.
Божевільний фізик

Функція Escape працює лише на відповідність. Зворотні нахили в місці призначення можуть все-таки зіпсувати речі.
ideaman42

4

Як каже Блер Конрад, string.replace це не підтримує.

Використовуйте регулярний вираз re.sub, але не забудьте спочатку уникнути рядка заміни. Зауважте, що немає опцій прапорців в 2.6 для re.sub, тому вам доведеться використовувати вбудований модифікатор'(?i)' (або RE-об’єкт, див. Відповідь Блера Конрада). Крім того, ще одна помилка полягає в тому, що підданий буде обробляти ухили зворотної косої риски в тексті заміни, якщо задано рядок. Щоб цього уникнути, можна замість цього перейти в лямбда.

Ось функція:

import re
def ireplace(old, repl, text):
    return re.sub('(?i)'+re.escape(old), lambda m: repl, text)

>>> ireplace('hippo?', 'giraffe!?', 'You want a hiPPO?')
'You want a giraffe!?'
>>> ireplace(r'[binfolder]', r'C:\Temp\bin', r'[BinFolder]\test.exe')
'C:\\Temp\\bin\\test.exe'

4

Ця функція використовує str.replace()і re.findall()функції, і функції. Він замінить всі входження patternв stringс replв регістронезавісімого чином.

def replace_all(pattern, repl, string) -> str:
   occurences = re.findall(pattern, string, re.IGNORECASE)
   for occurence in occurences:
       string = string.replace(occurence, repl)
       return string

3

Для цього не потрібно RegularExp

def ireplace(old, new, text):
    """ 
    Replace case insensitive
    Raises ValueError if string not found
    """
    index_l = text.lower().index(old.lower())
    return text[:index_l] + new + text[index_l + len(old):] 

3
Хороший, проте це не змінює всіх випадків старого з новим, а лише з першим явищем.
rsmoorthy

5
Він менш читабельний, ніж версія регулярного виразів. Тут не потрібно винаходити колесо.
Йоганнес Біттнер

Було б цікаво провести порівняння продуктивності між цією та оновленою версіями, це може бути швидше, що має значення для деяких додатків. Або це може бути повільніше, оскільки це робить більше роботи в інтерпретованому Python.
D Coetzee

2

Цікаве спостереження щодо деталей та варіантів синтаксису:

Python 3.7.2 (теги / v3.7.2: 9a3ffc0492, 23 грудня 2018, 23:09:28) [MSC v.1916 64 біт (AMD64)] у програмі win32

import re
old = "TREEROOT treeroot TREerOot"
re.sub(r'(?i)treeroot', 'grassroot', old)

'низовий низовий низовий'

re.sub(r'treeroot', 'grassroot', old)

"TREEROOT низовий TREerOot"

re.sub(r'treeroot', 'grassroot', old, flags=re.I)

'низовий низовий низовий'

re.sub(r'treeroot', 'grassroot', old, re.I)

"TREEROOT низовий TREerOot"

Отже, префікс (? I) у виразі відповідності або додавання "flags = re.I" як четвертий аргумент призведе до невідповідності регістру. АЛЕ, використовуючи лише "re.I" як четвертий аргумент, це не призводить до невідповідності регістру.

Для порівняння

re.findall(r'treeroot', old, re.I)

['TREEROOT', 'treeroot', 'TREerOot']

re.findall(r'treeroot', old)

['корінь дерева']


Це не дає відповіді на запитання. будь ласка, відредагуйте свою відповідь, щоб переконатися, що вона покращилась щодо інших відповідей, вже наявних у цьому питанні.
хонгі

1

У мене не було перетворено на послідовності евакуації (прокрутіть трохи вниз), тому я зазначив, що re.sub перетворює зворотні коси втекли символи для виходу з послідовностей.

Щоб запобігти цьому, я написав наступне:

Замініть корпус нечутливим.

import re
    def ireplace(findtxt, replacetxt, data):
        return replacetxt.join(  re.compile(findtxt, flags=re.I).split(data)  )

Крім того, якщо ви хочете, щоб його замінили символи втечі, як і інші відповіді тут, які набувають особливого значення символи bashslash, перетворені на схожі послідовності, просто розшифруйте свою знахідку або замініть рядок. У Python 3, можливо, доведеться зробити щось на зразок .decode ("unicode_escape") # python3

findtxt = findtxt.decode('string_escape') # python2
replacetxt = replacetxt.decode('string_escape') # python2
data = ireplace(findtxt, replacetxt, data)

Випробувано на Python 2.7.8

Сподіваюся, що це допомагає.


0

ніколи раніше не публікував відповіді, і ця тема справді стара, але я придумав ще одне роздуття і подумав, що я можу отримати вашу відповідь. Я не досвідчений в програмуванні Python, тому, якщо є привабливі недоліки до цього, будь-ласка, вкажіть їх, оскільки його добре вивчають: )

i='I want a hIPpo for my birthday'
key='hippo'
swp='giraffe'

o=(i.lower().split(key))
c=0
p=0
for w in o:
    o[c]=i[p:p+len(w)]
    p=p+len(key+w)
    c+=1
print(swp.join(o))

2
Для навчання: зазвичай, коли ви здійснюєте пошук і заміну на рядок, краще не спочатку перетворювати його на масив. Ось чому перша відповідь, мабуть, найкраща. Хоча він використовує зовнішній модуль, він обробляє рядок як одну цілу рядок. Це також трохи зрозуміліше, що відбувається в процесі.
isaaclw

Для навчання: дуже важко для розробника, який не має контексту, читати цей код і розшифровувати, що він робить :)
Todd
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.