একক স্থানের সাথে নন-এএসসিআইআই অক্ষরগুলি প্রতিস্থাপন করুন


244

আমার সমস্ত অ- ASCII (\ x00- \ x7F) অক্ষর স্থানের সাথে প্রতিস্থাপন করতে হবে। আমি অবাক হয়েছি যে পাইথনে এটি মৃত-সহজ নয়, যদি না আমি কিছু মিস করি। নিম্নলিখিত ফাংশনটি কেবল সমস্ত ASCII অক্ষর মুছে ফেলে:

def remove_non_ascii_1(text):

    return ''.join(i for i in text if ord(i)<128)

এবং এটি একটি অক্ষর কোড পয়েন্টের বাইটের পরিমাণ অনুসারে ফাঁকা পরিমাণের সাথে (যেমন অক্ষরটি 3 স্পেস দিয়ে প্রতিস্থাপন করা হয়েছে) অ-এসসিআইআই অক্ষরকে প্রতিস্থাপন করে:

def remove_non_ascii_2(text):

    return re.sub(r'[^\x00-\x7F]',' ', text)

আমি কীভাবে সমস্ত অ ASCII অক্ষরকে একটি একক স্থানের সাথে প্রতিস্থাপন করতে পারি?

এর অগণ্য এর অনুরূপ তাই প্রশ্ন , কোনটি ঠিকানা চরিত্র প্রতিস্থাপন হিসাবে বিরোধিতা করার stripping , এবং অতিরিক্ত সমস্ত অ-ASCII নয় এমন অক্ষর একটি নির্দিষ্ট অক্ষর মোকাবেলার।


46
বাহ, আপনি এতগুলি লিঙ্ক দেখানোর জন্য সত্যই চেষ্টা করেছেন। দিনটি নতুন হওয়ার সাথে সাথেই +1!
sha0w_wa1k3r

3
মনে হচ্ছে আপনি এই একটি স্ট্যাকওভারফ্লো.com
স্টুয়ার্ট

আমি সমস্যা আছে এমন একটি উদাহরণ ইনপুট দেখতে আগ্রহী।
dstromberg

5
@ স্টুয়ার্ট: ধন্যবাদ, তবে এটিই আমি প্রথম উল্লেখ করছি first
dotancohen

1
@dstromberg: আমি প্রশ্ন একটি সমস্যাযুক্ত উদাহরণ চরিত্র উল্লেখ: । এটা এই লোক
dotancohen

উত্তর:


243

আপনার ''.join()অভিব্যক্তি ফিল্টার করছে , অ-এএসসিআইআই-তে কিছু অপসারণ করছে; পরিবর্তে আপনি শর্তসাপেক্ষ এক্সপ্রেশন ব্যবহার করতে পারেন:

return ''.join([i if ord(i) < 128 else ' ' for i in text])

এটি একের পর এক অক্ষর পরিচালনা করে এবং প্রতিস্থাপিত অক্ষরে প্রতি একটি স্থান ব্যবহার করবে।

আপনার নিয়মিত অভিব্যক্তিটি কেবল একটি স্থানের সাথে পরপর অ-ASCII অক্ষরগুলি প্রতিস্থাপন করা উচিত :

re.sub(r'[^\x00-\x7F]+',' ', text)

+সেখানে নোট করুন ।


18
@ ডিস্ট্রোমবার্গ: ধীর; str.join() দরকার একটি তালিকা দেখুন (এটি মান উপর দুইবার পাস করব), এবং একটি জেনারেটর অভিব্যক্তি প্রথম এক রূপান্তর করা হবে। এটিকে একটি তালিকা উপলব্ধি দেওয়া সহজতর দ্রুত simply এই পোস্টটি দেখুন ।
মার্টিজন পিটারস

1
আপনি যদি কোনও ইউটিএফ -8 বাইট স্ট্রিং সরবরাহ করেন তবে কোডের প্রথম টুকরোটি অক্ষর অনুযায়ী একাধিক ফাঁকা প্রবেশ করান।
মার্ক র্যানসম

@MarkRansom: আমি এই পাইথন 3. হতে অভিমানী ছিল
Martijn Pieters

2
প্রশ্নের " অক্ষরটি 3 স্পেস দিয়ে প্রতিস্থাপন করা হয়েছে" ইঙ্গিত দেয় যে ইনপুটটি বাইস্টেরিং (ইউনিকোড নয়) এবং তাই পাইথন 2 ব্যবহৃত হয় (অন্যথায় ''.joinব্যর্থ হবে)। ওপি যদি ইউনিকোড কোডপয়েন্ট অনুযায়ী একক স্থান চায় তবে প্রথমে ইনপুটটি ইউনিকোডে ডিকোড করা উচিত।
jfs

এটি আমাকে অনেক সাহায্য করেছে!
মুহাম্মদ হাসিব

55

আপনার জন্য আপনার মূল স্ট্রিংয়ের সর্বাধিক অনুরূপ উপস্থাপনা পাবেন আমি ইউনিফিড কোডটি মডিউলটি প্রস্তাব করছি :

from unidecode import unidecode
def remove_non_ascii(text):
    return unidecode(unicode(text, encoding = "utf-8"))

তারপরে আপনি এটিকে একটি স্ট্রিংয়ে ব্যবহার করতে পারেন:

remove_non_ascii("Ceñía")
Cenia

আকর্ষণীয় পরামর্শ, তবে এটি ধরে নিয়েছে যে ব্যবহারকারী অ্যাস্কেইকে ইউনিকেডকোডের নিয়মগুলি কী হতে চান তা পছন্দ করে। তবে এটি কেন অন্য জায়গাগুলির সাথে প্রতিস্থাপন করার জন্য তারা ফাঁকা জায়গাগুলি জোর দেয় সে সম্পর্কে প্রশ্নকারীকে একটি ফলোআপ প্রশ্ন উত্থাপন করে?
jxramos

ধন্যবাদ, এটি একটি ভাল উত্তর। এটি এই প্রশ্নের উদ্দেশ্যে কাজ করে না কারণ আমি যে ডেটা নিয়ে কাজ করছি তার বেশিরভাগেরই এসএসআইআই-এর মতো উপস্থাপনা থাকে না। যেমন דותן। তবে, সাধারণ অর্থে এটি দুর্দান্ত, আপনাকে ধন্যবাদ!
dotancohen

1
হ্যাঁ, আমি জানি যে এটি এই প্রশ্নের পক্ষে কাজ করে না , তবে আমি এই সমস্যাটি সমাধান করার চেষ্টা করে এখানে পৌঁছেছি, তাই আমি ভেবেছিলাম যে আমি কেবল নিজের সমস্যার সমাধান করব, যা আমি মনে করি @ ডোটানকোহেন হিসাবে লোকদের কাছে খুব সাধারণ অ-এস্কি অক্ষর সহ সারাক্ষণ।
আলভারো ফুয়েন্তে

অতীতে এই জাতীয় জিনিসগুলির সাথে কিছু সুরক্ষিত দুর্বলতা ছিল। আপনি কীভাবে এটি বাস্তবায়ন করবেন তা যত্নবান হন!
deweydb


22

জন্য চরিত্র প্রক্রিয়াকরণ, ইউনিকোড স্ট্রিং ব্যবহার করুন:

PythonWin 3.3.0 (v3.3.0:bd8afb90ebf2, Sep 29 2012, 10:57:17) [MSC v.1600 64 bit (AMD64)] on win32.
>>> s='ABC马克def'
>>> import re
>>> re.sub(r'[^\x00-\x7f]',r' ',s)   # Each char is a Unicode codepoint.
'ABC  def'
>>> b = s.encode('utf8')
>>> re.sub(rb'[^\x00-\x7f]',rb' ',b) # Each char is a 3-byte UTF-8 sequence.
b'ABC      def'

তবে মনে রাখবেন যে আপনার স্ট্রিংটিতে পচে যাওয়া ইউনিকোড অক্ষর রয়েছে (পৃথক অক্ষর এবং অ্যাকসেন্ট চিহ্নগুলির সমন্বয়, উদাহরণস্বরূপ):

>>> s = 'mañana'
>>> len(s)
6
>>> import unicodedata as ud
>>> n=ud.normalize('NFD',s)
>>> n
'mañana'
>>> len(n)
7
>>> re.sub(r'[^\x00-\x7f]',r' ',s) # single codepoint
'ma ana'
>>> re.sub(r'[^\x00-\x7f]',r' ',n) # only combining mark replaced
'man ana'

ধন্যবাদ, এটি একটি গুরুত্বপূর্ণ পর্যবেক্ষণ is আপনি যদি চিহ্নগুলি সংযুক্ত করার ক্ষেত্রে পরিচালনা করার কোনও যৌক্তিক উপায় খুঁজে পান তবে আমি আনন্দের সাথে প্রশ্নের একটি অনুগ্রহ যুক্ত করব। আমি মনে করি যে কেবল মিশ্রিত চিহ্নটি অপসারণ করা কিন্তু অনিয়ন্ত্রিত চরিত্রটি একা রেখে দেওয়া ভাল।
dotancohen

1
একটি আংশিক সমাধান ud.normalize('NFC',s)চিহ্ন সংযুক্ত করতে ব্যবহার করা হয়, তবে সমস্ত সংমিশ্রণ সংমিশ্রণ একক কোডপয়েন্ট দ্বারা প্রতিনিধিত্ব করা হয় না। ud.category()চরিত্রটির দিকে তাকানোর জন্য আপনার আরও চৌকস সমাধান দরকার ।
মার্ক টোলোনেন

1
@ ডোটানকোহেন: ইউনিকোডে "ব্যবহারকারী-অনুভূত চরিত্র" সম্পর্কে ধারণা রয়েছে যা বেশ কয়েকটি ইউনিকোড কোডপয়েন্টগুলিকে বিস্তৃত করতে পারে। \X(এক্সটেন্ডেড গ্রাফিয়াম ক্লাস্টার) রেজেেক্স ( regexমডিউল দ্বারা সমর্থিত ) এই জাতীয় অক্ষরগুলির সাথে পুনরাবৃত্তি করতে দেয় (দ্রষ্টব্য: "গ্রাফিমগুলি অগত্যা চরিত্রের ক্রমগুলি একত্রিত করে না, এবং চরিত্রের ক্রমগুলি সংমিশ্রিত করে গ্রাফিমগুলি হয় না" )।
jfs

10

প্রতিস্থাপনের চরিত্রটি যদি হতে পারে '?' কোনও জায়গার পরিবর্তে, তবে আমি পরামর্শ দেব result = text.encode('ascii', 'replace').decode():

"""Test the performance of different non-ASCII replacement methods."""


import re
from timeit import timeit


# 10_000 is typical in the project that I'm working on and most of the text
# is going to be non-ASCII.
text = 'Æ' * 10_000


print(timeit(
    """
result = ''.join([c if ord(c) < 128 else '?' for c in text])
    """,
    number=1000,
    globals=globals(),
))

print(timeit(
    """
result = text.encode('ascii', 'replace').decode()
    """,
    number=1000,
    globals=globals(),
))

ফলাফল:

0.7208260721400134
0.009975979187503592

প্রতিস্থাপন? পরে প্রয়োজনে অন্য একটি চরিত্র বা স্থান সহ, এবং আপনি এখনও দ্রুত হতে চাই।
মরিটজ

7

এটা কেমন?

def replace_trash(unicode_string):
     for i in range(0, len(unicode_string)):
         try:
             unicode_string[i].encode("ascii")
         except:
              #means it's non-ASCII
              unicode_string=unicode_string[i].replace(" ") #replacing it with a single space
     return unicode_string

1
যদিও এটি বরং অবহেলিত, এটি খুব পঠনযোগ্য। ধন্যবাদ.
dotancohen

1
ইউনিকোড হ্যান্ডলিংয়ের জন্য +1 ... @ ডটানকোহেন আইএমএনএসএইচও "পঠনযোগ্য" বোঝায় "ব্যবহারিক" যা "মার্জিত" তে যুক্ত করে, তাই আমি "কিছুটা
অবৈধ

3

একটি নেটিভ এবং দক্ষ পদ্ধতির হিসাবে, আপনাকে ordঅক্ষরগুলি ব্যবহার করতে বা কোনও লুপের দরকার নেই । কেবল asciiত্রুটি সহ এনকোড করুন এবং উপেক্ষা করুন।

নিম্নলিখিতটি কেবল অ-অ্যাস্কি অক্ষরগুলি সরিয়ে ফেলবে:

new_string = old_string.encode('ascii',errors='ignore')

এখন আপনি যদি মুছে ফেলা অক্ষরগুলি প্রতিস্থাপন করতে চান তবে নীচেরটি করুন:

final_string = new_string + b' ' * (len(old_string) - len(new_string))

অজগর 3 এ, এটি encodeএকটি বাইস্টেরিং ফিরিয়ে দেবে, তাই এটি মনে রাখবেন। এছাড়াও, এই পদ্ধতিটি নিউলাইনের মতো অক্ষরগুলি ছড়িয়ে দেবে না।
কাইল গিবসন

-1

সম্ভাব্যভাবে অন্য কোনও প্রশ্নের জন্য, তবে আমি আমার @ অ্যালভেরোর উত্তরটির সংস্করণ সরবরাহ করছি (ইউনিসেডকোড ব্যবহার করে)। আমি আমার স্ট্রিংগুলিতে একটি "নিয়মিত" স্ট্রিপ করতে চাইছি, যেমন সাদা অংশের অক্ষরগুলির জন্য আমার স্ট্রিংয়ের শুরু এবং শেষ, এবং তারপরে কেবলমাত্র "হোয়াইটস্পেস" অক্ষরগুলিকে একটি "নিয়মিত" স্থানের সাথে প্রতিস্থাপন করতে হবে, অর্থাৎ

"Ceñíaㅤmañanaㅤㅤㅤㅤ"

প্রতি

"Ceñía mañana"

,

def safely_stripped(s: str):
    return ' '.join(
        stripped for stripped in
        (bit.strip() for bit in
         ''.join((c if unidecode(c) else ' ') for c in s).strip().split())
        if stripped)

আমরা প্রথমে সমস্ত অ-ইউনিকোড স্পেসকে একটি নিয়মিত জায়গার সাথে প্রতিস্থাপন করি (এবং এটিতে আবার যোগ দিতে),

''.join((c if unidecode(c) else ' ') for c in s)

এবং তারপরে আমরা অজগরটির সাধারণ বিভাজন দিয়ে আবার ভাগ করে নিই এবং প্রতিটি "বিট" কেটে ফেলি,

(bit.strip() for bit in s.split())

এবং সর্বশেষে আবার তাদের সাথে যোগ দিন, তবে কেবল যদি স্ট্রিং কোনও ifপরীক্ষায় উত্তীর্ণ হয় ,

' '.join(stripped for stripped in s if stripped)

এবং এটি দিয়ে, safely_stripped('ㅤㅤㅤㅤCeñíaㅤmañanaㅤㅤㅤㅤ')সঠিকভাবে ফিরে আসে 'Ceñía mañana'

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.