大文字と小文字を区別しない置換


回答:


217

stringタイプはこれをサポートしていません。おそらく、re.IGNORECASEオプションを指定した正規表現のsubメソッドを使用することをお勧めします。

>>> 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( 'hippo')、 'giraffe'、 'I hippo for my my birthday')
D Coetzee

3
文字列だけでre.escapeするのはなぜですか?ありがとう。
Elena

8
@Elena、それはには必要ありませんが'hippo'、to-replace値が関数に渡された場合に役立つので、他の何よりも本当に良い例です。
ブレアコンラッド

2
有するだけでなくre.escape、あなたの針に注意この回答は避けることができない、ここで別のトラップ、ありますstackoverflow.com/a/15831118/1709587は:以来、re.subプロセスがエスケープシーケンスを、で述べたようにdocs.python.org/library/re.html#re .sub、置換文字列内のすべてのバックスラッシュをエスケープするか、ラムダを使用する必要があります。
Mark Amery

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)
Louis Yang

re.subPython 2.7以降、このフラグのみをサポートしていることに注意してください。
fuenfundachtzig

47

1行で:

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の答えを続けると、この関数は1つではなく、すべての古いものを新しいものに変更します-大文字と小文字を区別しない方法で。

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 2017年

あなたがしなければならないすべては正規表現をエスケープすることです:受け入れられた答えはこれよりはるかに短くて読みやすいです。
マッド

エスケープは一致する場合にのみ機能し、宛先のバックスラッシュはまだ混乱する可能性があります。
ideasman42 '9/10/19

4

ブレア・コンラッドが言うように、string.replaceはこれをサポートしていません。

正規表現を使用しますが、re.sub最初に置換文字列をエスケープすることを忘れないでください。の2.6にはflags-option re.subがないため、埋め込み修飾子'(?i)'(またはREオブジェクト、Blair Conradの回答を参照)を使用する必要があることに注意してください。また、別の落とし穴は、文字列が指定されている場合、subが置換テキストのバックスラッシュエスケープを処理することです。これを回避するには、代わりにラムダを渡すことができます。

ここに関数があります:

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でのstringrepl大文字と小文字を区別しないように。

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
正規表現バージョンよりも読みにくくなっています。ここでホイールを再発明する必要はありません。
Johannes Bittner、2011年

このバージョンと投票されたバージョンのパフォーマンスを比較することは興味深いでしょう。これは、一部のアプリケーションにとって重要な、より高速な場合があります。または、解釈されたPythonでより多くの作業を行うため、速度が遅くなる可能性があります。
D Coetzee

2

構文の詳細とオプションに関する興味深い観察:

Python 3.7.2(tags / v3.7.2:9a3ffc0492、Dec 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)プレフィックスを使用するか、4番目の引数として「flags = re.I」を追加すると、大文字と小文字を区別しない一致になります。ただし、4番目の引数として「re.I」のみを使用しても、大文字と小文字を区別しない一致は行われません。

比較のために、

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

['TREEROOT'、 'treeroot'、 'TREerOot']

re.findall(r'treeroot', old)

['ツリールート']


これは質問に対する答えを提供しません。回答を編集して、この質問にすでに存在する他の回答を確実に改善してください。
hongsy

1

私は\ tをエスケープシーケンス(少し下にスクロール)に変換していたので、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

これまでに回答を投稿したことがなく、このスレッドは本当に古いですが、別の解決策を思いついて、私はあなたの反応を得ることができると考えました)

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
学習用:通常、文字列を検索して置換するときは、最初に文字列を配列に変換する必要がない方がよいでしょう。そのため、最初の答えがおそらく最良です。外部モジュールを使用している間は、文字列を1つの文字列全体として扱います。また、プロセスで何が起こっているかについても、少し明確になっています。
isaaclw 2012

学習用:コンテキストのない開発者がこのコードを読んで、その動作を解読するのは非常に困難です:)
Todd
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.