Pythonの文字列から特定の文字を削除する


546

Pythonを使用して文字列から特定の文字を削除しようとしています。これは私が今使っているコードです。残念ながら、それは文字列に対して何もしないようです。

for char in line:
    if char in " ?.!/;:":
        line.replace(char,'')

これを正しく行うにはどうすればよいですか?


23
5年以上になりfilterますが、関数とラムダ式の使用についてはどうでしょうかfilter(lambda ch: ch not in " ?.!/;:", line)。かなり簡潔で効率的でもあると思います。もちろん、名前を割り当てる必要がある新しい文字列を返します。
ジョンレッド

3
@JohnRed:実際には、文字のリストを返すイテレータを返しますが、これを回答に含めれば、私たちの何人かはそれを賛成票で投票します。
ビル・ベル


@BillBell:PS:Python3のイテレータであり、Python2の文字列、タプル、またはリストです
serv-inc

回答:


626

Pythonの文字列は不変です(変更できません)。このため、の効果はline.replace(...)、古い文字列を変更するのではなく、単に新しい文字列を作成することです。それらの文字を削除して、変数に新しい値を割り当てるには、それを再バインド(割り当て)する必要がありlineます。

また、あなたがそれをしているやり方は、比較的遅いです。また、二重にネストされた構造を見て、少し複雑なことが起こっていることを一瞬考える熟練したpythonatorを少し混乱させる可能性もあります。

Python 2.6以降のPython 2.xバージョン*以降、代わりにを使用できますstr.translate(ただし、Python 3の違いについては以下をお読みください)。

line = line.translate(None, '!@#$')

または正規表現置換 re.sub

import re
line = re.sub('[!@#$]', '', line)

大括弧で囲まれた文字は文字クラスを構成します。lineそのクラスに含まれるすべての文字は、2番目のパラメーターでsub空の文字列に置き換えられます。

Python 3では、文字列はUnicodeです。少し違う方法で翻訳する必要があります。kevpieは回答の1つに関するコメントでこれについて言及しており、のドキュメントにstr.translate記載されています

translateUnicode文字列のメソッドを呼び出すときに、上記で使用した2番目のパラメーターを渡すことはできません。またNone、最初のパラメーターとして渡すこともできません。代わりに、変換テーブル(通常は辞書)を唯一のパラメーターとして渡します。この表は、文字の順序値(つまり、ordそれらの呼び出しの結果)を、それらを置き換える必要がある文字の順序値にマップするか、または(私Noneたちにとっては)削除する必要があることを示しています。

したがって、Unicode文字列で上記のダンスを行うには、次のようなものを呼び出します。

translation_table = dict.fromkeys(map(ord, '!@#$'), None)
unicode_line = unicode_line.translate(translation_table)

ここでdict.fromkeys、以下をmap含む辞書を簡潔に生成するために使用されます

{ord('!'): None, ord('@'): None, ...}

さらに簡単に、別の答えが言うように、適切な変換テーブルを作成します。

unicode_line = unicode_line.translate({ord(c): None for c in '!@#$'})

または、次のコマンドで同じ変換テーブルを作成しますstr.maketrans

unicode_line = unicode_line.translate(str.maketrans('', '', '!@#$'))

*以前のPythonとの互換性のために、「null」変換テーブルを作成して、の代わりに渡すことができますNone

import string
line = line.translate(string.maketrans('', ''), '!@#$')

ここでstring.maketransは、変換テーブルを作成するために使用されます。これは、順序値0〜255の文字を含む文字列です。


26
Python3では、line.translate引数が1つしか取られず、最初の解決策は機能しません
marczoid

33
python3では、str.translate()は2番目の引数を取りません。だから、あなたの答えは line.translate({ord(i):None for i in '!@#$'})
naveen

1
他の文字と同じです。Pythonでは、一重引用符または二重引用符のペアを使用できます。つまり"'"、文字セットを記述するだけです。
2015年

2
上記の@naveenのコメントは私にとってうまくいきました。Pythony 2.7.13。私の場合、「」と「」の文字をnotes = notes.translate({ord(i):None for i in '\"\''})
取り除きました

1
Python 3では、を使用できますunicode_line.translate(str.maketrans('', '', '!@#$'))。またはunicode_line.translate(dict.fromkeys(map(ord, '!@#$')))
Martijn Pieters

234

私はここでポイントを逃していますか、それとも次のとおりですか?

string = "ab1cd1ef"
string = string.replace("1","") 

print string
# result: "abcdef"

ループに入れます:

a = "a!b@c#d$"
b = "!@#$"
for char in b:
    a = a.replace(char,"")

print a
# result: "abcd"

26
これにより、各ループで文字列のコピーが作成されますが、これは望ましくない場合があります。また、それは非常に良いPythonではありません。:Pythonであなたの代わりにこのようなループだろうfor char in b: a=a.replace(char,"")
elgehelge

2
システムクラスと重複するユーザー定義変数を使用することはお勧めできません。STRの代わりに変数STRINGを使用し、CHARの代わりにCを使用することをお勧めします。
Ayrat

string=string.replace("1","")代わりにする必要があります。あなたはこれをあなたの例のループ部分で言ったが、ほとんどの人はそのような単純な質問のために最初に少し手でコードをいじるまで、あなたの答えまでそれを読むことはないだろう。
CodeMed

良い解決策ですが、他の1つほどPython-eskではありません。
スティーブ

45
>>> line = "abc#@!?efg12;:?"
>>> ''.join( c for c in line if  c not in '?:!/;' )
'abc#@efg12'

'' 'や "などの別の文字列区切り文字を使用する
ALisboa

1
禁止されている文字がたくさんある場合は、最初にセットにしてコードを高速化できます。blacklist = set('?:!/;')その後''.join(c for c in line if c not in blacklist)
ボリス

32

re.subPython 3.5以降の正規表現で簡単に

re.sub('\ |\?|\.|\!|\/|\;|\:', '', line)

>>> import re

>>> line = 'Q: Do I write ;/.??? No!!!'

>>> re.sub('\ |\?|\.|\!|\/|\;|\:', '', line)
'QDoIwriteNo'

説明

正規表現(正規表現)、|論理的ORと\実際の正規表現のコマンドであるかもしれないスペースや特殊文字をエスケープします。一方sub置換は、この場合は空の文字列''です。


22

文字列内の特定の文字のみを許可するという逆の要件については、補集合演算子で正規表現を使用できます[^ABCabc]。たとえば、ASCII文字、数字、ハイフンを除くすべてを削除するには、次のように入力します。

>>> import string
>>> import re
>>>
>>> phrase = '  There were "nine" (9) chick-peas in my pocket!!!      '
>>> allow = string.letters + string.digits + '-'
>>> re.sub('[^%s]' % allow, '', phrase)

'Therewerenine9chick-peasinmypocket'

Pythonの正規表現のドキュメント

範囲内にない文字は、セットを補完することで一致させることができます。セットの最初の文字がの場合、セットに'^'ないすべての文字が一致します。たとえば、[^5]「5」以外のすべての文字に一致し、以外の[^^]すべての文字に一致します '^'^セットの最初の文字でない場合、特別な意味はありません。


19

質問者はほとんどそれを持っていました。Pythonのほとんどのことと同様に、答えはあなたが考えるよりも簡単です。

>>> line = "H E?.LL!/;O:: "  
>>> for char in ' ?.!/;:':  
...  line = line.replace(char,'')  
...
>>> print line
HELLO

ネストされたif / forループを実行する必要はありませんが、各文字を個別にチェックする必要があります。


はい私は知っています、おそらく手遅れですが、それを逃れるならうまくいくはずです。このように:line = line.replace( '`'、 '')読みます:learnpythonthehardway.org/book/ex10.html
Aiyion.Prime '26

すべての文字に新しい文字列を割り当てるため、これはおそらくパフォーマンスが
悪い


11
>>> s = 'a1b2c3'
>>> ''.join(c for c in s if c not in '123')
'abc'

2
私の回答は元の質問に対する解決策を提供しますが、なぜ私の解決策が理想的でないのかについてのフィードバックにも(おそらくOPも)興味を持っていました。新しい質問を作成し、この質問をコンテキストとして参照する必要がありますか?
2015年

これは私の投票を取得します。Python簡潔
Steve

9

文字列はPythonでは不変です。このreplaceメソッドは、置換後に新しい文字列を返します。試してください:

for char in line:
    if char in " ?.!/;:":
        line = line.replace(char,'')

どのようにしてラインを反復し、同時に変更できますか?
eumiro

1
@eumiro:反復は元のに 続きますline
Greg Hewgill、

知っておきたい!したがって、配列を反復処理する場合は、元の配列を反復処理します。イテレータの反復は不可能です。
eumiro

9

ビルトインのフィルター機能の使用をまだ誰も推奨していなかったことに驚きました。

    import operator
    import string # only for the example you could use a custom string

    s = "1212edjaq"

数値ではないすべてのものを除外したいとします。組み込みのフィルターメソッド「...は、ジェネレーター式(if(item)の反復可能アイテムのアイテム)に相当します」[ Python 3 Builtins:Filter ]

    sList = list(s)
    intsList = list(string.digits)
    obj = filter(lambda x: operator.contains(intsList, x), sList)))

Python 3では、これは

    >>  <filter object @ hex>

印刷された文字列を取得するには、

    nums = "".join(list(obj))
    print(nums)
    >> "1212"

どのようにフィルターするかわかりませんが効率の点でランク付けされるが、リスト内包などを行う場合の使用方法を知ることは良いことです。

更新

論理的には、フィルターは機能するので、リスト内包表記を使用することもできます。ラムダはプログラミング関数の世界のウォールストリートヘッジファンドマネージャーであるため、私が読んだ内容からより効率的であると考えられます。もう1つの利点は、インポートが不要なワンライナーであることです。たとえば、上記で定義したのと同じ文字列「s」を使用すると、

      num = "".join([i for i in s if i.isdigit()])

それでおしまい。戻り値は、元の文字列の数字であるすべての文字の文字列です。

許容/非許容文字の特定のリストがある場合は、リスト内包表記の「if」部分のみを調整する必要があります。

      target_chars = "".join([i for i in s if i in some_list]) 

または代わりに

      target_chars = "".join([i for i in s if i not in some_list])

とにかくoperator.contains使っているなら使う理由はないlambdalambda x: operator.contains(intsList, x)スペルを入力する必要がありますlambda x: x in intsList。または、Cレベルのチェックを取得しようとしている場合は、intsList.__contains__lambdaまったく)トリックを実行します。
ShadowRanger

8

を使用するとfilter、必要なのは1行だけです。

line = filter(lambda char: char not in " ?.!/;:", line)

これは文字列を反復可能として扱い、がlambda返された場合はすべての文字をチェックしますTrue

>>> help(filter)
Help on built-in function filter in module __builtin__:

filter(...)
    filter(function or None, sequence) -> list, tuple, or string

    Return those items of sequence for which function(item) is true.  If
    function is None, return the items that are true.  If sequence is a tuple
    or string, return the same type, else return a list.

4

このタスクを実行するいくつかの可能な方法を次に示します。

def attempt1(string):
    return "".join([v for v in string if v not in ("a", "e", "i", "o", "u")])


def attempt2(string):
    for v in ("a", "e", "i", "o", "u"):
        string = string.replace(v, "")
    return string


def attempt3(string):
    import re
    for v in ("a", "e", "i", "o", "u"):
        string = re.sub(v, "", string)
    return string


def attempt4(string):
    return string.replace("a", "").replace("e", "").replace("i", "").replace("o", "").replace("u", "")


for attempt in [attempt1, attempt2, attempt3, attempt4]:
    print(attempt("murcielago"))

PS:代わりに "?。!/ ;:"を使用します。例では母音を使用しています...そうです、 "murcielago"はコウモリを言うスペイン語の単語です...すべての母音が含まれているので面白い単語です:)

PS2:パフォーマンスに興味がある場合は、次のような簡単なコードでこれらの試みを測定できます。

import timeit


K = 1000000
for i in range(1,5):
    t = timeit.Timer(
        f"attempt{i}('murcielago')",
        setup=f"from __main__ import attempt{i}"
    ).repeat(1, K)
    print(f"attempt{i}",min(t))

私の箱ではあなたが得るでしょう:

attempt1 2.2334518376057244
attempt2 1.8806643818474513
attempt3 7.214925774955572
attempt4 1.7271184513757465

したがって、この特定の入力では、attempt4が最も速いようです。


1
不要なlistを作成していattempt1"aeiou"、単純にするためにタプルを書き換えることができます(削除する[]、リストを作成せずにジェネレーターになります)。で使い捨ての中間文字列を大量に作成し、1つのパスで使用できる場所attemt2で正規表現の複数のアプリケーションをattempt3使用r'[aeiou]'します。それぞれに欠点があります-さまざまな方法を確認できるのは良いことですが、それらを適切な試行になるように修正してください
Patrick Artner '22

1
@PatrickArtner正解です...このタスクを達成するために私が心に抱いた数十の方法から、遅いものを選びました(OPにいくつかの最も簡単なものを見せたいと思っていました)...みんな、もう答えた古いスレッドにもっと力を入れようと動機を失った他のスレッドを閉じたので... :)。ポイントをありがとう。
BPL、

ただ酒は、「attempt4を」新しいものを追加しただけのために...測定が、私は1つが速いものでなければならないと考えていない@PatrickArtner [OK]を...
BPL

1
@PatrickArtner Edited ... attempt4は、試行の小さなセットの中で最速でした。とにかく、私はこれのものにこれ以上の時間を
BPL

3

これが私のPython 2/3互換バージョンです。翻訳APIが変更されたため。

def remove(str_, chars):
    """Removes each char in `chars` from `str_`.

    Args:
        str_: String to remove characters from
        chars: String of to-be removed characters

    Returns:
        A copy of str_ with `chars` removed

    Example:
            remove("What?!?: darn;", " ?.!:;") => 'Whatdarn'
    """
    try:
        # Python2.x
        return str_.translate(None, chars)
    except TypeError:
        # Python 3.x
        table = {ord(char): None for char in chars}
        return str_.translate(table)

dict.fromkeys(map(ord, '!@#$'))地図の作成に使用します。
Martijn Pieters

map一般に、リスト/辞書/セット/ジェネレータの内包よりも読みにくいです。グイドが言語からそれを削除たかったほど。の使用fromkeysも少し賢く、ドキュメントのチェックが必要です。
ブライスギンタ2017

1
@MartijnPieters:Python 3の場合str.maketrans('', '', chars)ord変換とdict構成をすべて一度に処理します(これはとペアになるように設計されているため、意図がより明確であることは言うまでもありませんstr.translate)。
ShadowRanger

1
#!/usr/bin/python
import re

strs = "how^ much for{} the maple syrup? $20.99? That's[] ricidulous!!!"
print strs
nstr = re.sub(r'[?|$|.|!|a|b]',r' ',strs)#i have taken special character to remove but any #character can be added here
print nstr
nestr = re.sub(r'[^a-zA-Z0-9 ]',r'',nstr)#for removing special character
print nestr

スピーチマークですか?reには、コードをエスケープ'して文字列と見なすためのバックスラッシュがあります。docs.python.org/2/library/re.html
JasTonAChair

1

これはどう:

def text_cleanup(text):
    new = ""
    for i in text:
        if i not in " ?.!/;:":
            new += i
    return new

1
提供するソリューションについてもう少し説明を追加して、回答を詳しく説明していただけますか?
abarisone 2015年

リストに追加してから結合を使用する方が連結よりも効率的です
OneCricketeer

1

また、関数を使用して、リストを使用して異なる種類の正規表現やその他のパタ​​ーンを置き換えることもできます。これにより、正規表現、文字クラス、および本当に基本的なテキストパターンを混在させることができます。HTML要素のような多くの要素を置き換える必要がある場合、それは本当に役に立ちます。

*注意:Python 3.xで動作します

import re  # Regular expression library


def string_cleanup(x, notwanted):
    for item in notwanted:
        x = re.sub(item, '', x)
    return x

line = "<title>My example: <strong>A text %very% $clean!!</strong></title>"
print("Uncleaned: ", line)

# Get rid of html elements
html_elements = ["<title>", "</title>", "<strong>", "</strong>"]
line = string_cleanup(line, html_elements)
print("1st clean: ", line)

# Get rid of special characters
special_chars = ["[!@#$]", "%"]
line = string_cleanup(line, special_chars)
print("2nd clean: ", line)

関数string_cleanupでは、文字列xと不要なリストを引数として受け取ります。要素またはパターンのリスト内の各アイテムについて、代替が必要な場合は行われます。

出力:

Uncleaned:  <title>My example: <strong>A text %very% $clean!!</strong></title>
1st clean:  My example: A text %very% $clean!!
2nd clean:  My example: A text very clean

1

私が使用する私の方法はおそらく効率的には機能しないでしょうが、それは非常に単純です。スライスとフォーマットを使用して、異なる位置にある複数の文字を一度に削除できます。次に例を示します。

words = "things"
removed = "%s%s" % (words[:3], words[-1:])

これにより、「this」という単語が保持された「removed」になります。

書式設定は、印刷文字列の途中で変数を印刷する場合に非常に役立ちます。変数のデータ型が後に続くを使用して、任意のデータ型を挿入できます。すべてのデータ型は%sを使用でき、浮動小数点(別名10進数)および整数は%dを使用できます。

スライスは、ストリングの複雑な制御に使用できます。私が入れたとき[:3]の言葉を、それは私が第四文字に(コロンは番号の前に、これは「と最初から」意味する場合)最初から文字列中のすべての文字を選択することができます(これは、第4回を含みキャラクター)。理由3が4番目の位置まで等しいのは、Pythonが0から始まるためです。次に、word [-1:]を置くと、最後から2番目の文字(コロンは数字の後ろ)を意味します。-1を指定すると、Pythonは最初の文字ではなく、最後の文字から数えます。この場合も、Pythonは0から始まります。つまり、word [-1:]基本的に、「最後から2番目の文字から文字列の終わりまでを意味します。

そこで、削除したい文字の前の文字と後の文字を切り取って挟むことで、不要な文字を削除できます。ソーセージのようなものだと考えてください。真ん中は汚れているので、取り除きたいです。必要な2つの端を切り取って、中央に不要な部分がないようにまとめます。

複数の連続する文字を削除したい場合は、[](スライス部分)で数字をシフトするだけです。または、異なる位置から複数のキャラクターを削除したい場合は、一度に複数のスライスを一緒に挟むだけです。

例:

 words = "control"
 removed = "%s%s" % (words[:2], words[-2:])

削除された「クール」に等しい。

words = "impacts"
removed = "%s%s%s" % (words[1], words[3:5], words[-1])

削除された「macs」に等しい。

この場合には、[3:5]の文字を意味する位置にある文字を介して3 位置(最終位置の文字を除く)5。

覚えておいて、Pythonは0でカウントを開始し、あなたが同様に必要になりますので、。


0

これを試してください:

def rm_char(original_str, need2rm):
    ''' Remove charecters in "need2rm" from "original_str" '''
    return original_str.translate(str.maketrans('','',need2rm))

このメソッドはpython 3.5.2でうまく機能します


0

reモジュールの正規表現の置換を使用できます。^式を使用すると、文字列から必要なものを正確に選択できます。

    import re
    text = "This is absurd!"
    text = re.sub("[^a-zA-Z]","",text) # Keeps only Alphabets
    print(text)

これへの出力は「Thisisabsurd」になります。^記号の後に指定されたものだけが表示されます。


0

文字列メソッドreplaceは、元の文字列を変更しません。オリジナルをそのままにし、変更されたコピーを返します。

あなたが欲しいものは次のようなものです: line = line.replace(char,'')

def replace_all(line, )for char in line:
    if char in " ?.!/;:":
        line = line.replace(char,'')
    return line

ただし、文字が削除されるたびに新しい文字列を作成することは非常に非効率的です。代わりに以下をお勧めします:

def replace_all(line, baddies, *):
    """
    The following is documentation on how to use the class,
    without reference to the implementation details:

    For implementation notes, please see comments begining with `#`
    in the source file.

    [*crickets chirp*]

    """

    is_bad = lambda ch, baddies=baddies: return ch in baddies
    filter_baddies = lambda ch, *, is_bad=is_bad: "" if is_bad(ch) else ch
    mahp = replace_all.map(filter_baddies, line)
    return replace_all.join('', join(mahp))

    # -------------------------------------------------
    # WHY `baddies=baddies`?!?
    #     `is_bad=is_bad`
    # -------------------------------------------------
    # Default arguments to a lambda function are evaluated
    # at the same time as when a lambda function is
    # **defined**.
    #
    # global variables of a lambda function
    # are evaluated when the lambda function is
    # **called**
    #
    # The following prints "as yellow as snow"
    #
    #     fleece_color = "white"
    #     little_lamb = lambda end: return "as " + fleece_color + end
    #
    #     # sometime later...
    #
    #     fleece_color = "yellow"
    #     print(little_lamb(" as snow"))
    # --------------------------------------------------
replace_all.map = map
replace_all.join = str.join

-1

1つ下..正規表現の概念を使用せずに..

ipstring ="text with symbols!@#$^&*( ends here"
opstring=''
for i in ipstring:
    if i.isalnum()==1 or i==' ':
        opstring+=i
    pass
print opstring

-1

Python 3.5では

例えば、

os.rename(file_name, file_name.translate({ord(c): None for c in '0123456789'}))

文字列からすべての数値を削除するには



-1

再帰的な分割: s = string; chars =削除する文字

def strip(s,chars):
if len(s)==1:
    return "" if s in chars else s
return strip(s[0:int(len(s)/2)],chars) +  strip(s[int(len(s)/2):len(s)],chars)

例:

print(strip("Hello!","lo"))    #He!

-1

#ディレクトリの各ファイルについて、ファイル名を変更

   file_list = os.listdir (r"D:\Dev\Python")

   for file_name in file_list:

       os.rename(file_name, re.sub(r'\d+','',file_name))

-1

以下のアプローチでも機能します

line = "a,b,c,d,e"
alpha = list(line)
        while ',' in alpha:
            alpha.remove(',')
finalString = ''.join(alpha)
print(finalString)

出力: abcde


-2
>>> # Character stripping
>>> a = '?abcd1234!!'
>>> t.lstrip('?')
'abcd1234!!'
>>> t.strip('?!')
'abcd1234'

10
文字列の最初または最後からのみ文字を削除します
divenex
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.