मैं ASCII में UTF-8 में पर्शियन अंकों को यूरोपीय अंकों में कैसे बदल सकता हूं?


16

फारसी अंकों में, यूरोपीय अंकों में ۰۱۲۳۴۵۶۷۸۹बराबर है 0123456789

मैं UTF-8ASCII में पर्शियन नंबर (इन ) कैसे बदल सकता हूं ?

उदाहरण के लिए, मैं चाहता हूँ ۲۱बनने के लिए 21


1
दिलचस्प, ऐसा लगता है जैसे echo "۰۱۲۳۴۵۶۷۸۹" | iconv -f UTF-8 -t ascii//TRANSLITइसे संभाल नहीं करता है ...
Kusalananda

@ कुसलानंद ने काम नहीं किया
بارپابابا

3
@ कुसलानंद: क्या यह वास्तव में अप्रत्याशित है? जैसा कि मैंने समझा कि iconvविभिन्न एन्कोडिंग में वर्णों को मैप करना बस यहाँ है, लेकिन ये ऐसे अक्षर (पूर्वी अरबी अंक) हैं जिनका ASCII में कोई समकक्ष नहीं है, आप बस उन्हें कुछ समान रूप में परिवर्तित कर सकते हैं, लेकिन यह केवल एक तरफ़ा है।
phk

3
खैर, मुझे पूरा यकीन नहीं iconvथा कि क्या करने में सक्षम है और क्या करने में सक्षम नहीं है। मैं उम्मीद कर रहा था कि थॉट का उपयोग //TRANSLITकरने में मदद मिलेगी, लेकिन यह नहीं हुआ।
Kusalananda

1
क्या आपको आदेश को उलटने की भी आवश्यकता है? मुझे पता है कि अरबी अंकों को दाएं-बाएं बाएं ओर लिखा जाता है, और लैटिन अंक बड़े-बाएं-बाएं-दाएं (प्रिंट में या स्क्रीन पर समान दिखते हैं, लेकिन स्मृति में उलट होते हैं) होते हैं। क्या फारसी एक ही है?
टोबी स्पाइट

जवाबों:


6

हम इस तथ्य का लाभ उठा सकते हैं कि फारसी अंकों के UNICODE कोड बिंदु लगातार हैं और 0 से 9 तक ऑर्डर किए गए हैं :

$ printf '%b' '\U06F'{0..9}
۰۱۲۳۴۵۶۷۸۹

इसका मतलब है कि अंतिम हेक्स अंक दशमलव मान है:

$ echo $(( $(printf '%d' "'۲") & 0xF ))
2

यह इस सरल लूप को रूपांतरण उपकरण बनाता है:

#!/bin/bash
(   ### Use a locale that use UTF-8 to make the script more reliable.
    ### Maybe something like LC_ALL=fa_IR.UTF-8 for you?.
    LC_ALL=en_US.UTF-8
    a="$1"
    while (( ${#a} > 0 )); do
        # extract the last hex digit from the UNICODE code point
        # of the first character in the string "$a":
        printf '%d' $(( $(printf '%d' "'$a") & 15 ))
        a=${a#?}    ## Remove one character from $a
    done
)
echo

इसका उपयोग इस प्रकार है:

$ sefr.sh ۰۱۲۳۴۵۶۷۸۹
0123456789

$ sefr.sh ۲۰۱
201

$ sefr.sh ۲۱
21

ध्यान दें कि यह कोड अरबी और लैटिन अंकों को भी बदल सकता है (भले ही मिश्रित हो):

$ sefr.sh ۴4٤۵5٥۶6٦۷7٧۸8٨۹9٩
444555666777888999

$ sefr.sh ٤٧0٠٦7١٣3٥۶٦۷
4700671335667

बहुत बहुत धन्यवाद, यह बहुत अच्छा समाधान है ,, और मेरा सवाल है, इस कमांड में printf '% d' '' double 'दोहरा-उद्धरण का उपयोग क्यों करते हैं?
بارپابابا

@ बाबी यह एक दोहरा उद्धरण नहीं है, यह प्रिंटफ को एक तर्क देने का एक तरीका है जो एक एकल उद्धरण के साथ शुरू होता है :। यह भी लिखा जा सकता था '"۰'। कारण यह है कि अगर किसी एकल उद्धरण 'या दोहरे उद्धरण के साथ तर्क शुरू होता है तो प्रिंटफ़ यूनिकोड कोड बिंदु देगा "। पाठ के लिए इस लिंक से थोड़ा पहले खोजें "यदि अग्रणी चरित्र एकल-उद्धरण या डबल-उद्धरण है"

@Babyy फारसी, अरबी और लैटिन (भले ही मिश्रित) को परिवर्तित करने के लिए कोड बढ़ाया गया है।

27

चूंकि यह संख्याओं का एक निश्चित सेट है, आप इसे हाथ से कर सकते हैं:

$ echo ۲۱ | LC_ALL=en_US.UTF-8 sed -e 'y/۰۱۲۳۴۵۶۷۸۹/0123456789/'
21

(या उपयोग कर रहे हैं tr, लेकिन अभी तक GNU tr नहीं)

अपने वर्णों को पहचानने के en_US.utf8लिए अपने लोकल को सेट करना (या अक्षरों को सेट करना बेहतर है) sed

के साथ perl:

$ echo "۲۱" |
  perl -CS -MUnicode::UCD=num -MUnicode::Normalize -lne 'print num(NFKD($_))'
21

आवश्यकता निर्धारित करना LC_ALLताकि हर एक यूनिकोड वर्ण को भी इस प्रकार माना जाए sed, है ना?
phk

@ एफके: हां, अपडेट देखें।
कोउन्ग्लम

सब कुछ एक सीड स्क्रिप्ट क्यों होना चाहिए? क्या हमने trइस सटीक उद्देश्य के लिए आविष्कार नहीं किया ?
केविन

3
@ केविन अन्य जवाब को देखें trकि यह हर जगह कैसे काम नहीं करता है। यह भी ध्यान रखें कि कुछ उपकरण बाइट्स से निपटने के लिए अनुकूलित हैं जबकि अन्य पात्रों के साथ काम करने के लिए हैं, यूनिकोड के साथ (विशेष रूप से यूटीएफ -8) यह बहुत बड़ा अंतर बनाता है।
फक

यह मेरे लिए OS X 10.10.5 / GNU बैश 4.3 पर काम नहीं करता है। पर्याप्त रूप से मुझे स्पष्ट सेटिंग को हटाने की आवश्यकता है LC_ALLLC_ALLमेरे वातावरण में भी सेट नहीं है (लेकिन LANGसेट है en_GB.UTF-8)। उपरोक्त कोड के साथ, मुझे त्रुटि "sed: 1:" y / ... / ... ": बदलना स्ट्रिंग समान लंबाई नहीं हैं"।
कोनराड रुडोल्फ

15

पाइथन के लिए unidecodeऐसी लाइब्रेरी है जो सामान्य रूप से इस तरह के रूपांतरणों को संभालती है: https://pypi.python.org/pypi/Unidecode

पायथन 2 में:

>>> from unidecode import unidecode
>>> unidecode(u"۰۱۲۳۴۵۶۷۸۹")
'0123456789'

पायथन 3 में:

>>> from unidecode import unidecode
>>> unidecode("۰۱۲۳۴۵۶۷۸۹")
'0123456789'

Https://stackoverflow.com/q/8087381/2261442 पर SO थ्रेड संबंधित हो सकता है।

/ संपादित करें: जैसा कि वांडर नुटा ने टिप्पणियों में बताया है और जैसा कि यूनीडॉब पेज पर उल्लेख किया गया है, इसका एक शेल संस्करण भी है unidecode( /usr/local/bin/यदि नीचे स्थापित किया गया है pip):

$ echo '۰۱۲۳۴۵۶۷۸۹' | unidecode
0123456789

2
यूनिडबॉस लाइब्रेरी एक उपयोगिता भी कहलाती है (बिना unidecodeकिसी कारण के ) जो आपके पाइथन 3 स्निपेट के समान होती है। बस echo '۰۱۲۳۴۵۶۷۸۹' | unidecodeकाम करना चाहिए।
वंडर नौट

@ रैंडर - अजगर-यूनिडॉब के डेबियन पैकेज उपयोगिता कार्यक्रम को जहाज नहीं करता है, इसलिए इस तरह के प्लेटफार्मों पर लंबा रूप आवश्यक हो सकता है (मुझे अपस्ट्रीम से स्रोत टारबॉल में एक नहीं मिला, इसलिए शायद कार्यक्रम कुछ और द्वारा जोड़ा गया है आपका वितरण?)
टोबी स्पाइट

@TobySpeight यदि आप इसका उपयोग कर pipइसे वहां स्थापित कर रहे हैं।
phk

@TobySpeight उपयोगिता अपस्ट्रीम टारबॉल में है unidecode/util.py- अजीब है कि डेबियन इसे शामिल नहीं करता है। (संपादित करें: आह, रहस्य सुलझ गया। डेबियन पैकेज पुराना है और उपयोगिता से अधिक पुराना है।)
वांडर नौटा

7

एक शुद्ध बैश संस्करण:

#!/bin/bash

number="$1"

number=${number//۱/1}
number=${number//۲/2}
number=${number//۳/3}
number=${number//۴/4}
number=${number//۵/5}
number=${number//۶/6}
number=${number//۷/7}
number=${number//۸/8}
number=${number//۹/9}
number=${number//۰/0}

echo "Result is $number"

मेरे गेंटू मशीन में परीक्षण किया है और यह काम करता है।

./convert ۱۳۲
Result is 132

एक लूप के रूप में, वर्णों की सूची दी गई है (0 से 9 तक) परिवर्तित करने के लिए:

#!/bin/bash
conv() ( LC_ALL=en_US.UTF-8
         local n="$2"
         for ((i=0;i<${#1};i++)); do
              n=${n//"${1:i:1}"/"$i"}
         done
         printf '%s\n' "$n"
       )

conv "۰۱۲۳۴۵۶۷۸۹" "$1"

और के रूप में इस्तेमाल किया:

$ convert ۱۳۲
132

एक और (बल्कि ओवरकिल) का उपयोग कर रास्ता grep:

#!/bin/bash

nums=$(echo "$1" | grep -o .)
result=()

for i in $nums
do
    case $i in
        ۱)
            result+=1
            ;;
        ۲)
            result+=2
            ;;
        ۳)
            result+=3
            ;;
        ۴)
            result+=4
            ;;
        ۵)
            result+=5
            ;;
        ۶)
            result+=6
            ;;
        ۷)
            result+=7
            ;;
        ۸)
            result+=8
            ;;
        ۹)
            result+=9
            ;;
        ۰)
            result+=0
            ;;
    esac
done
echo "Result is $result"

1
शुद्ध बैश, को छोड़कर grep। वास्तव में, मैं उस लाइन को नहीं समझता, और न ही आप सेट क्यों नहीं करते result=0। यदि आप $1फारसी अंकों के अलावा अन्य चीजों में शामिल हैं, तो क्या आप अत्यधिक सतर्क हैं ?
Kusalananda

@ कुसलानंद वह रेखा फारसी अंकों को अंक में पढ़ती है। इसे लूप-सक्षम बनाता है।
कॉफमेग

1
दस सरल प्रतिस्थापन तेज होता है ... number=${number//۱/1}आदि, और से बचने के हैं echoऔर grep
कुसलानंद an

1
@ कुसलानंद नाइस। उसे बदल दिया। अब यह शुद्ध बैश है! ;-)
कॉफमेग

@coffeMug: off 132 नो 123: D
باربابابا

3

चूँकि iconvयह ग्रॉस नहीं हो सकता, इसलिए कॉल का अगला पोर्ट trयूटिलिटी का उपयोग करना होगा :

$ echo "۲۱" | tr '۰۱۲۳۴۵۶۷۸۹' '0123456789'
21

tr वर्णों के एक सेट का दूसरे में अनुवाद करता है, इसलिए हम इसे फ़ारसी अंकों के सेट को लैटिन अंकों के सेट में अनुवाद करने के लिए कहते हैं।

EDIT : जैसा कि उपयोगकर्ता @cuonglm बताते हैं। इस गैर जीएनयू की आवश्यकता है tr, उदाहरण के लिए trकिसी Mac, और यह भी जरूरी है कि $LC_CTYPEकरने के लिए सेट कर दिया जाता en_US.UTF-8


2
ध्यान दें कि यह GNU tr के साथ काम नहीं करेगा, जो मल्टी-बाइट वर्णों का समर्थन नहीं करता है।
कोउंगलम

1
अरे मेरा। सिली जीएनयू। ;-)
Kusalananda

और आपको अपने लोकेल को भी सेट करने की आवश्यकता है जो यूनिकोड का समर्थन करता है, जैसे en_US.utf8
१२:०६ पर congongl
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.