ASCII olmayan karakterleri nasıl kaldırabilirim ancak Python kullanarak nokta ve boşluk bırakabilirim?


101

Bir .txt dosyasıyla çalışıyorum. Dosyadan ASCII olmayan karakterler içermeyen bir metin dizesi istiyorum. Ancak boşluk ve nokta bırakmak istiyorum. Şu anda onları da çıkarıyorum. İşte kod:

def onlyascii(char):
    if ord(char) < 48 or ord(char) > 127: return ''
    else: return char

def get_my_string(file_path):
    f=open(file_path,'r')
    data=f.read()
    f.close()
    filtered_data=filter(onlyascii, data)
    filtered_data = filtered_data.lower()
    return filtered_data

Boşluk ve nokta bırakmak için onlyascii () 'yi nasıl değiştirmeliyim? Çok karmaşık olmadığını düşünüyorum ama çözemiyorum.


Açıklama için teşekkürler (içtenlikle) John. Boşlukların ve noktaların ASCII karakterler olduğunu anladım. Ancak, yalnızca ASCII olmayan karakterleri kaldırmaya çalışırken ikisini de istemeden kaldırıyordum. Sorumun aksini nasıl ima ettiğini anlıyorum.

@PoliticalEconomist: Sorununuz hala yeterince belirtilmemiş. Cevabımı gör.
John Machin

Yanıtlar:


188

String.printable kullanarak dizeden yazdırılamayan tüm karakterleri aşağıdaki gibi filtreleyebilirsiniz :

>>> s = "some\x00string. with\x15 funny characters"
>>> import string
>>> printable = set(string.printable)
>>> filter(lambda x: x in printable, s)
'somestring. with funny characters'

makinemdeki string.printable şunları içerir:

0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~ \t\n\r\x0b\x0c

DÜZENLEME: Python 3'te, filtre bir yinelenebilir döndürür. Bir dizeyi geri almanın doğru yolu şudur:

''.join(filter(lambda x: x in printable, s))

2
Sıra 48'in altındaki yazdırılabilir karakterlerde ne var?
joaquin

38
Kullanmanın tek sorunu, filterbir yinelenebilir döndürmesidir. (Liste sıkıştırma yaparken bu gerekli çünkü benim yaptığım gibi) bir dize geri gerekiyorsa o zaman bunu: ''.join(filter(lambda x: x in string.printable, s).
cjbarth

5
@cjbarth - yorum python 3'e özgüdür, ancak çok kullanışlıdır. Teşekkürler!
undershock

7
Neden normal ifadeyi kullanmaz: re.sub(r'[^\x00-\x7f]',r'', your-non-ascii-string). Bu konuya bakın stackoverflow.com/a/20079244/658497
Noam Manos

1
@NoamManos bu, Join ... filter ... lambda çözümünde benim için 4-5 kat daha hızlıydı, teşekkürler.
artfulrobot

95

Farklı bir codec bileşenine geçmenin kolay bir yolu, encode () veya decode () kullanmaktır. Sizin durumunuzda, ASCII'ye dönüştürmek ve desteklenmeyen tüm sembolleri yok saymak istiyorsunuz. Örneğin, İsveççe harf å bir ASCII karakteri değildir:

    >>>s = u'Good bye in Swedish is Hej d\xe5'
    >>>s = s.encode('ascii',errors='ignore')
    >>>print s
    Good bye in Swedish is Hej d

Düzenle:

Python3: str -> bayt -> str

>>>"Hej då".encode("ascii", errors="ignore").decode()
'hej d'

Python2: unicode -> str -> unicode

>>> u"hej då".encode("ascii", errors="ignore").decode()
u'hej d'

Python2: str -> unicode -> str (ters sırada deşifre edin ve kodlayın)

>>> "hej d\xe5".decode("ascii", errors="ignore").encode()
'hej d'

16
AnlıyorumUnicodeDecodeError: 'ascii' codec can't decode byte 0xc2 in position 27
Xodarap777

2
Kopyala yapıştır ile dizeye gerçek unicode karakterini koyduğumda bu hatayı aldım. U'thestring 'kodlama olarak bir dize belirttiğinizde doğru çalışır.
Ben Liyanage

2
Yalnızca Py3'te çalışır, ancak zariftir.
2016

7
@ Xodarap777 ile aynı hatayı alanlar için: önce dizeyi .decode () ve sadece bu kodlamadan sonra yapmalısınız. Örneğins.decode('utf-8').encode('ascii', errors='ignore')
Spc_555


6

Sorunuz belirsiz; birlikte alındığında ilk iki cümle, boşluk ve "noktanın" ASCII olmayan karakterler olduğuna inandığınızı gösterir. Bu yanlış. Ord (char) <= 127 gibi tüm karakterler ASCII karakterleridir. Örneğin, işleviniz şu karakterleri hariç tutuyor! "# $% & \ '() * +, -. / Ancak başka birkaç karakter de içerir, örneğin [] {}.

Lütfen geri çekilin, biraz düşünün ve ASCII sözcüğünden bahsetmeden ne yapmaya çalıştığınızı ve ord (char)> = 128 gibi karakterlerin neden göz ardı edilebilir olduğunu düşündüğünüzü anlatmak için sorunuzu düzenleyin. Ayrıca: Python'un hangi sürümü? Giriş verilerinizin kodlaması nedir?

Lütfen kodunuzun tüm girdi dosyasını tek bir dize olarak okuduğunu ve başka bir yanıta yönelik yorumunuzun ("harika çözüm") verilerinizdeki yeni satırları umursamadığınız anlamına geldiğini unutmayın. Dosyanız aşağıdaki gibi iki satır içeriyorsa:

this is line 1
this is line 2

sonuç olurdu 'this is line 1this is line 2' ... gerçekten istediğin bu mu?

Daha büyük bir çözüm şunları içerecektir:

  1. filtre işlevi için daha iyi bir isim onlyascii
  2. bağımsız değişken korunacaksa, bir filtre işlevinin yalnızca doğru bir değer döndürmesi gerektiğinin tanınması:

    def filter_func(char):
        return char == '\n' or 32 <= ord(char) <= 126
    # and later:
    filtered_data = filter(filter_func, data).lower()

Bu cevap, OP'ye benzer bir şey sormak için gelen bizler için çok yararlıdır ve önerdiğiniz yanıt yararlı bir şekilde pitoniktir. Bununla birlikte, sizin yorumladığınız şekliyle (sık sık karşılaştığım) soruna daha etkili bir çözüm olmadığını garip buluyorum - karakter karakter, bu çok büyük bir dosyada çok uzun zaman alıyor.
Xodarap777

5

İngilizce olmayan harfleri kaldırmak için aşağıdaki kodu kullanabilirsiniz:

import re
str = "123456790 ABC#%? .(朱惠英)"
result = re.sub(r'[^\x00-\x7f]',r'', str)
print(result)

Bu geri dönecek

123456790 ABC #%? . ()


1

Yazdırılabilir ascii karakterleri istiyorsanız, muhtemelen kodunuzu şu şekilde düzeltmelisiniz:

if ord(char) < 32 or ord(char) > 126: return ''

bu, string.printabledönüşlerin ve sekmelerin ('\ t', '\ n', '\ x0b', '\ x0c' ve '\ r') olmaması dışında (@jterrace'den yanıt) ile eşdeğerdir, ancak şuna karşılık gelmez Sorunuzdaki aralık


1
Biraz daha basit: lambda x: 32 <= ord (x) <= 126
jterrace

bu string.printable ile aynı değildir çünkü string.whitespace'i dışarıda bırakır, ancak OP'nin istediği şey bu olabilir, \ n ve \ t gibi şeylere bağlıdır.
jterrace

@jterrace right, boşluk (ord 32) içerir ancak iade ve sekme içermez
joaquin

evet, sadece "bu string.printable ile eşdeğerdir" üzerine yorum yapıyorum, ancak doğru değil
jterrace

Cevabı düzenledim, teşekkürler! Dikkatlice okumazsanız, OP sorusu yanıltıcıdır.
joaquin

1

Fluent Python (Ramalho) ile kendi yöntemimle çalışmak - şiddetle tavsiye edilir. Bölüm 2'den esinlenerek anlama tek-satırları listeleyin:

onlyascii = ''.join([s for s in data if ord(s) < 127])
onlymatch = ''.join([s for s in data if s in
              'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'])

Bu, madde işaretleri, derece sembolü, telif hakkı sembolü, Yen sembolü vb. Gibi standart ASCII sembollerine izin vermez. Ayrıca, ilk örneğiniz, istenmeyen BELL gibi yazdırılamayan semboller içerir.
SherylHohman
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.