422

Tôi đang cố xóa các ký tự cụ thể khỏi chuỗi bằng Python. Đây là mã tôi đang sử dụng ngay bây giờ. Thật không may, nó dường như không làm gì với chuỗi.

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

Làm thế nào để tôi làm điều này đúng?

|
538

Chuỗi trong Python là bất biến (không thể thay đổi). Bởi vì điều này, hiệu quả của line.replace(...)chỉ là tạo ra một chuỗi mới, thay vì thay đổi chuỗi cũ. Bạn cần rebind (gán) nó để linebiến đó lấy giá trị mới, với các ký tự đó bị xóa.

Ngoài ra, cách bạn đang làm nó sẽ là loại chậm, tương đối. Nó cũng có thể hơi khó hiểu với những con trăn có kinh nghiệm, những người sẽ nhìn thấy một cấu trúc gấp đôi và nghĩ trong giây lát rằng một cái gì đó phức tạp hơn đang diễn ra.

Bắt đầu trong Python 2.6 và các phiên bản Python 2.x mới hơn *, thay vào đó, bạn có thể sử dụng str.translate(nhưng đọc về sự khác biệt của Python 3):

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

hoặc thay thế biểu thức chính quy bằng re.sub

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

Các ký tự được đặt trong ngoặc tạo thành một lớp ký tự . Bất kỳ ký tự linenào trong lớp đó được thay thế bằng tham số thứ hai thành sub: một chuỗi rỗng.

Trong Python 3, chuỗi là Unicode. Bạn sẽ phải dịch một chút khác nhau. kevpie đề cập đến điều này trong một bình luận về một trong những câu trả lời, và nó được ghi chú trong tài liệu chostr.translate .

Khi gọi translatephương thức của chuỗi Unicode, bạn không thể truyền tham số thứ hai mà chúng ta đã sử dụng ở trên. Bạn cũng không thể vượt qua Nonenhư tham số đầu tiên, hoặc thậm chí là bảng dịch từ đó string.maketrans. Thay vào đó, bạn vượt qua một từ điển như là tham số duy nhất. Từ điển này ánh xạ các giá trị thứ tự của các ký tự (nghĩa là kết quả của việc gọi ordchúng) đến các giá trị thứ tự của các ký tự sẽ thay thế chúng, hoặc một cách hữu ích cho chúng tôi Noneđể xóa chúng.

Vì vậy, để thực hiện điệu nhảy trên với một chuỗi Unicode, bạn sẽ gọi một cái gì đó như

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

Ở đây dict.fromkeysmapđược sử dụng để tạo ra một từ điển ngắn gọn chứa

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

Thậm chí đơn giản hơn, như một câu trả lời khác đặt nó , tạo từ điển tại chỗ:

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

* để tương thích với các Pythons trước đó, bạn có thể tạo bảng dịch "null" để thay thế None:

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

Ở đây string.maketransđược sử dụng để tạo bảng dịch , đây chỉ là một chuỗi chứa các ký tự có giá trị thứ tự từ 0 đến 255.

|
  • 1

    Trong Python3, line.translatechỉ mất một đối số và giải pháp đầu tiên sẽ không hoạt động

    – Hồ Thu Thủy 09:19:57 20/11/2012
  • 1

    @marczoid: Cảm ơn, đã thêm một ghi chú cho hiệu ứng đó.

    – Nguyễn Đức 17:11:19 20/11/2012
  • 1

    Trong python3, str.translate () không lấy đối số thứ 2. Vì vậy, câu trả lời của bạn sẽ trở thành line.translate({ord(i):None for i in '!@#$'})

    – Nguyễn Ngọc Trâm 12:17:43 12/01/2014
  • 1

    Giống như bất kỳ nhân vật khác. Python cho phép bạn sử dụng các cặp dấu ngoặc đơn hoặc dấu ngoặc kép. Vì vậy, bạn chỉ cần viết "'"cho bộ ký tự.

    – Bùi Huệ Nghi 20:14:09 26/11/2015
  • 1

    Nhận xét của @ naveen ở trên đã làm việc cho tôi. Kim tự tháp 2.7.13. Trong trường hợp của tôi, tôi muốn lột đồ "và 'nhân vật:notes = notes.translate({ord(i):None for i in '\"\''})

    – Lê Minh Hỷ 14:18:11 14/03/2017
183

Tôi có thiếu điểm ở đây không, hay chỉ là như sau:

>>> string = "ab1cd1ef"
>>> string.replace("1","")
'abcdef'
>>>

Đặt nó trong một vòng lặp:

>>>
>>> a = "a!b@c#d$"
>>> b = "!@#$"
>>> for char in b:
...     a = a.replace(char,"")
...
>>> print a
abcd
>>>
|
  • 1

    Điều này sẽ tạo một bản sao của chuỗi trong mỗi vòng lặp, điều này có thể không được mong muốn. Ngoài ra nó không phải là Python rất tốt. Trong Python, bạn sẽ lặp như thế này thay vào đó:for char in b: a=a.replace(char,"")

    – Hồ Thu Thủy 14:05:23 18/10/2014
  • 1

    sử dụng các biến do người dùng định nghĩa chồng lấp các lớp hệ thống không phải là một ý tưởng tốt. Bạn nên sử dụng biến STRING thay vì STR và C thay vì CHAR.

    – Nguyễn Đức 14:06:36 26/08/2016
37
>>> line = "abc#@!?efg12;:?"
>>> ''.join( c for c in line if  c not in '?:!/;' )
'abc#@efg12'
|
  • 1

    Cảm ơn nhiều !! Tôi đã cố xóa biểu tượng Yên Nhật khỏi chuỗi tôi đã phân tích cú pháp thông qua phản hồi XML http. Giải pháp này đã hoạt động và tránh được nhiều rắc rối về Unicode. # - - mã hóa: utf-8 - - yenSymbol = ord (u '\ u00A5') cpc = '' .join (c cho c trong cpcWithYen if ord (c)! = yenSymbol)

    – Ngô Hồng Khôi 12:48:34 22/01/2014
  • 1

    Làm thế nào tôi có thể loại bỏ `` ký tự ?????? tôi không thể làm điều này với bất kỳ cách nào trong số này

    – Dương Thụy Linh 08:37:04 31/01/2016
  • 1

    sử dụng một dấu phân cách chuỗi khác, chẳng hạn như '' 'hoặc "

    – Hoàng Chí Nam 20:00:02 01/06/2017
21

Dễ dàng với re.subPython 3.5

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

Thí dụ

>>> import re

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

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

Giải trình

Trong các biểu thức chính quy (regex), |là một OR logic và \thoát khỏi khoảng trắng và các ký tự đặc biệt có thể là các lệnh regex thực tế. sublà viết tắt của sự thay thế.

|
18

Đối với yêu cầu nghịch đảo chỉ cho phép một số ký tự nhất định trong chuỗi, bạn có thể sử dụng các biểu thức chính quy với toán tử bổ sung đã đặt [^ABCabc]. Ví dụ: để xóa mọi thứ trừ chữ ascii, chữ số và dấu gạch nối:

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

Từ tài liệu biểu thức chính quy python :

Các ký tự không nằm trong phạm vi có thể được khớp bằng cách bổ sung cho tập hợp. Nếu ký tự đầu tiên của bộ là '^', tất cả các ký tự không có trong bộ sẽ được khớp. Ví dụ: [^5]sẽ khớp với bất kỳ ký tự nào ngoại trừ '5' và [^^]sẽ khớp với bất kỳ ký tự nào ngoại trừ '^'. ^không có ý nghĩa đặc biệt nếu đó không phải là nhân vật đầu tiên trong bộ.

|
18

Người hỏi gần như đã có nó. Giống như hầu hết mọi thứ trong Python, câu trả lời đơn giản hơn bạn nghĩ.

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

Bạn không phải thực hiện điều lặp if / for lồng nhau, nhưng bạn cần kiểm tra từng ký tự riêng lẻ.

|
14
line = line.translate(None, " ?.!/;:")
|
10
>>> s = 'a1b2c3'
>>> ''.join(c for c in s if c not in '123')
'abc'
|
  • 1

    Câu trả lời của tôi không cung cấp giải pháp cho câu hỏi ban đầu, nhưng tôi cũng quan tâm (có lẽ cả OP cũng vậy) trong phản hồi về lý do giải pháp của tôi có thể không lý tưởng. Tôi có nên tạo một câu hỏi mới và tham khảo câu hỏi này cho ngữ cảnh không?

    – Ngô Hồng Khôi 21:05:47 19/10/2015
7

Chuỗi là bất biến trong Python. Các replacephương thức trả về một chuỗi mới sau khi thay thế. Thử:

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

Sử dụng filter, bạn chỉ cần một dòng

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

Điều này coi chuỗi là một lần lặp và kiểm tra mọi ký tự nếu lambdatrả về 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.
|
5

Tôi đã rất ngạc nhiên khi chưa có ai khuyến nghị sử dụng chức năng lọc dựng sẵn .

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

    s = "1212edjaq"

Nói rằng chúng tôi muốn lọc ra tất cả mọi thứ không phải là một số. Sử dụng phương thức dựng sẵn bộ lọc "... tương đương với biểu thức trình tạo (mục cho mục trong iterable if function (item))" [ Python 3 Buildins: Filter ]

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

Trong Python 3, nó trả về

    >>  <filter object @ hex>

Để có được một chuỗi in,

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

Tôi không chắc chắn làm thế nào bộ lọc xếp hạng về hiệu quả nhưng nó là một điều tốt để biết làm thế nào để sử dụng khi làm việc hiểu danh sách và như vậy.

CẬP NHẬT

Về mặt logic, vì bộ lọc hoạt động, bạn cũng có thể sử dụng khả năng hiểu danh sách và từ những gì tôi đã đọc, nó được cho là hiệu quả hơn vì lambdas là nhà quản lý quỹ phòng hộ trên phố của thế giới chức năng lập trình. Một điểm cộng nữa là nó là một lớp lót không yêu cầu nhập khẩu. Ví dụ: sử dụng cùng một chuỗi 's' được xác định ở trên,

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

Đó là nó. Trả về sẽ là một chuỗi gồm tất cả các ký tự là các chữ số trong chuỗi gốc.

Nếu bạn có một danh sách cụ thể các ký tự được chấp nhận / không thể chấp nhận, bạn chỉ cần điều chỉnh phần 'nếu' trong phần hiểu danh sách.

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

Hay cách khác,

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

    Không có lý do để sử dụng operator.containsnếu bạn đang sử dụng một lambdaanyway. lambda x: operator.contains(intsList, x)nên được đánh vần lambda x: x in intsListhoặc nếu bạn đang cố kiểm tra cấp độ C, intsList.__contains__(hoàn toàn không lambda) sẽ thực hiện thủ thuật.

    – Ngô Hồng Khôi 16:02:54 25/03/2019
3

Dưới đây là một số cách có thể để đạt được nhiệm vụ này:

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: Thay vì sử dụng "?! /;

PS2: Nếu bạn quan tâm đến hiệu suất, bạn có thể đo những lần thử này bằng một mã đơn giản như:

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

Trong hộp của tôi, bạn sẽ nhận được:

attempt1 2.2334518376057244
attempt2 1.8806643818474513
attempt3 7.214925774955572
attempt4 1.7271184513757465

Vì vậy, có vẻ như nỗ lực4 là cách nhanh nhất cho đầu vào cụ thể này.

|
  • 1

    Bạn đang tạo một không cần thiết listtrong attempt1và tuple có thể được viết lại để "aeiou"vì cớ sự đơn giản (loại bỏ []sẽ lần lượt ở vào một máy phát điện mà không cần tạo một danh sách). Bạn tạo ra vô số chuỗi trung gian vứt đi attemt2, bạn sử dụng nhiều ứng dụng của regex trong attempt3đó bạn có thể sử dụng r'[aeiou]'trong một lần. mỗi người đều có những sai sót - thật tuyệt khi thấy những cách khác nhau để làm mọi thứ, nhưng vui lòng sửa chúng thành những nỗ lực tốt

    – Lý Sơn Quyền 13:08:19 22/07/2018
  • 1

    @PatrickArtner Bạn hoàn toàn đúng ... từ hàng tá cách tôi đã nghĩ để đạt được nhiệm vụ này, tôi đã chọn những thứ chậm hơn (muốn hiển thị cho OP một số cách dễ nhất) ... Điều đó nói rằng, sau bạn Các bạn đã đóng chủ đề khác Tôi đã mất động lực để nỗ lực nhiều hơn cho chủ đề cũ đã trả lời này, vì vậy ... :). Cảm ơn cho các điểm mặc dù.

    – Hồ Hòa Bình 13:14:48 22/07/2018
  • 1

    @PatrickArtner Ok ... chỉ vì lợi ích đã thêm một cái mới, "nỗ lực 4" ... chưa được đo nhưng tôi nghĩ rằng cái đó nên là cái nhanh hơn

    – Hà Quangg 13:18:43 22/07/2018
  • 1

    @PatrickArtner Đã chỉnh sửa ... Eff4 là nhanh nhất trong số ít lần thử. Dù sao, tôi sẽ không lãng phí nhiều thời gian hơn với những thứ này :)

    – Nguyễn Hoàn Vi 13:39:37 22/07/2018
3
>>> # Character stripping
>>> a = '?abcd1234!!'
>>> t.lstrip('?')
'abcd1234!!'
>>> t.strip('?!')
'abcd1234'
|
3

Đây là phiên bản tương thích Python 2/3 của tôi. Kể từ khi dịch api đã thay đổi.

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)
|
  • 1

    Tôi sẽ sử dụng dict.fromkeys(map(ord, '!@#$'))để tạo bản đồ.

    – Lý Sơn Quyền 16:03:02 08/04/2017
  • 1

    mapnói chung là ít đọc hơn so với việc hiểu danh sách / dict / set / trình tạo. Đến nỗi Guido muốn loại bỏ nó khỏi ngôn ngữ . Sử dụng fromkeyscũng là một chút thông minh và yêu cầu kiểm tra tài liệu.

    – Hồ Hòa Bình 23:21:48 08/04/2017
  • 1

    @MartijnPieters: Đối với Python 3, nó chỉ nên str.maketrans('', '', chars)xử lý việc ordchuyển đổi và dictxây dựng tất cả trong một lần (không đề cập đến ý định khá rõ ràng hơn, vì nó được thiết kế để ghép nối str.translate).

    – Hà Quangg 16:04:44 25/03/2019
1

Bạn phải gán lại biến str của bạn:

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

Câu trả lời của bạn (> 20 ký tự)

Bằng cách click "Đăng trả lời", bạn đồng ý với Điều khoản dịch vụ, Chính sách bảo mật and Chính sách cookie của chúng tôi.

Không tìm thấy câu trả lời bạn tìm kiếm? Duyệt qua các câu hỏi được gắn thẻ hoặc hỏi câu hỏi của bạn.