نو

نویسه در Julia

4 تمرین

درباره‌ی نویسه

این موضوع بزرگی است! می‌توان درباره‌ی آن کتابی طولانی نوشت و چندین نفر هم این کار را کرده‌اند (در آمازون عبارت «unicode book» را جست‌وجو کنید تا چند نمونه ببینید).

تاریخچه‌ای بسیار کوتاه

پردازش نویسه‌ها در رایانه در دهه‌های پیشین بسیار ساده‌تر بود، زمانی که برنامه‌نویسان فرض می‌کردند انگلیسی تنها زبان مهم است. پس: ۲۶ حرف، بزرگ و کوچک، ۱۰ رقم، چند علامت نگارشی، به‌علاوه یک کد (0x07) برای به صدا درآوردن زنگ، و همه‌ی این‌ها در ۷ بیت جا می‌شد: مجموعه‌نویسه‌ی ASCII.

طبیعی بود که مردم بپرسند پس تکلیف à، ä و Ł چیست، بعد افراد دیگری بپرسند درباره‌ی ऄ، ஹ و ญ چه کنیم و جوان‌ترها هم ایموجی 😱 بخواهند. چه باید کرد؟

خلاصه‌اش این که بسیاری از افراد باهوش و صبور سال‌ها در کمیته‌ها عضویت داشتند و جزئیات مجموعه‌نویسه‌ی Unicode و کدگذاری‌هایی مثل UTF-8 را مشخص کردند و نرم‌افزارهای زیادی نیاز به بازنویسی بسیار پیچیده‌ای پیدا کردند. ضمناً باگ‌های جدید زیادی هم به وجود آمد.

برای این که همه‌چیز از کار نیفتد، طراحی Unicode/UTF-8 تضمین می‌کند که ۱۲۷ کد اول با ASCII یکسان باشند (حتی همان زنگ).

نویسه‌ها در Julia

زبان‌هایی که بعد از حدود ۲۰۰۵ طراحی شده‌اند این مزیت بزرگ را دارند که استاندارد Unicode نسبتاً پایداری از قبل وجود داشت.

Julia (که اولین بار در ۲۰۱۲ منتشر شد) می‌توانست فرض کند که همه‌چیز Unicode خواهد بود: نویسه‌ها، رشته‌ها، اسم متغیرها و توابع، عملگرهای ریاضی...

به گفته‌ی راهنما، «Julia برخورد با متن ساده‌ی ASCII را ساده و کارآمد می‌کند و کار با Unicode را تا حد امکان ساده و کارآمد.» به عبارت «تا حد امکان» توجه کنید؛ این بخش مهمی از این جمله است.

لیترال‌های نویسه با تک‌کوتیشن نوشته می‌شوند و با رشته‌هایی که در کوتیشن دوتایی نوشته می‌شوند فرق دارند.

این موضوع برای اهالی دنیای C/C++ بدیهی است، اما می‌تواند برای برنامه‌نویسان Python و JavaScript گیج‌کننده باشد.

julia> a = 'a'  # Roman alphabet
'a': ASCII/Unicode U+0061 (category Ll: Letter, lowercase)

julia> typeof(a)
Char

julia> jha = 'झ'  # Devanagari alphabet
'झ': Unicode U+091D (category Lo: Letter, other)

julia> typeof(jha)
Char


julia> '❤'  # heart emoji
'❤': Unicode U+2764 (category So: Symbol, other)

از این مثال‌ها می‌بینیم که نوع آن Char است و Julia اطلاعات بیشتری درباره‌ی دسته‌ی نویسه دارد.

اگر دقیق‌تر نگاه کنیم، می‌بینیم این نویسه‌ها را می‌توان با ۴ رقم هگزادسیمال نمایش داد. کل مجموعه‌نویسه به ۶ رقم هگز نیاز دارد.

به این اعداد «کد پوینت» می‌گویند و در حال حاضر از U+0000 تا U+10FFFF را در بر می‌گیرند. این‌ها در REPL نمایش داده می‌شوند، اما در کد از codepoints() استفاده کنید تا آن‌ها را به دست آورید.

تبدیل بین Char و Int ساده است:

julia> Int('a')
97

julia> Char(97)
'a': ASCII/Unicode U+0061 (category Ll: Letter, lowercase)

کامپایلر برخی از شکل‌های حساب عدد صحیح روی Charها را مجاز می‌داند:

julia> 'b' - 'a'  # interval, in alphabetic order
1

julia> 'b' + 'a'
ERROR: MethodError: no method matching +(::Char, ::Char)

julia> 'a' + 5
'f': ASCII/Unicode U+0066 (category Ll: Letter, lowercase)

julia> 'f' + ('A' - 'a')  # same as `uppercase('f')`
'F': ASCII/Unicode U+0046 (category Lu: Letter, uppercase)

توابع مربوط به نویسه‌ها

زیرمجموعه‌ای از توابع کار با رشته روی ورودی Char هم کار می‌کنند.

  • برای الفباهای مناسب، بزرگی و کوچکی حروف را با uppercase() و lowercase() تغییر دهید.
  • حالت حروف را با isuppercase() و islowercase() بررسی کنید.
  • نوع نویسه را با این توابع بررسی کنید:
    • isletter()، بسیاری از الفباها را پوشش می‌دهد
    • isdigit()، فقط ارقام ۰ تا ۹ را بررسی می‌کند
    • isnumeric()، گسترده‌تر از isdigit، پس برای ¾ و خطوط غیراروپایی مختلف true برمی‌گرداند
    • isxdigit()، ارقام هگزادسیمال
    • isascii()، نویسه‌ی پیش از Unicode
    • ispunct()، علائم نگارشی
    • isspace()، هر نویسه‌ی فاصله
    • isprint()، نویسه‌های قابل چاپ (متضاد آن iscntrl() است)
islowercase('A')  # false
uppercase('γ')  # 'Γ': Unicode U+0393 (category Lu: Letter, uppercase)
ispunct('@')  # true
isdigit('A')  # false
isxdigit('A')  # true

برای بررسی این که یک نویسه در یک رشته هست یا نه، in را داریم. دقت کنید که این با زیررشته‌ها فرق دارد:

# char search
julia> 'a' ∈ "xabcahliazlnkiw"
true

# substring search
julia> "a" ∈ "xabcahliazlnkiw"
use occursin(needle, haystack) for string containment

همچنین عبارت‌های باقاعده (موضوع یک مفهوم دیگر) جست‌وجو و دست‌کاری قدرتمندی را ممکن می‌کنند.

تبدیل‌های متقابل بردار Char و رشته

برای تبدیل رشته به بردار Char می‌توانیم از collect() استفاده کنیم.

برای تبدیل بردار Char به رشته، سازنده‌ی String() هست.

julia> s = "abcde"
"abcde"

julia> cv = collect(s)
5-element Vector{Char}:
 'a': ASCII/Unicode U+0061 (category Ll: Letter, lowercase)
 'b': ASCII/Unicode U+0062 (category Ll: Letter, lowercase)
 'c': ASCII/Unicode U+0063 (category Ll: Letter, lowercase)
 'd': ASCII/Unicode U+0064 (category Ll: Letter, lowercase)
 'e': ASCII/Unicode U+0065 (category Ll: Letter, lowercase)

julia> String(cv)
"abcde"

این با هر نویسه‌ای کار می‌کند، نه فقط ASCII.

julia> collect("❤,😱")
3-element Vector{Char}:
 '❤': Unicode U+2764 (category So: Symbol, other)
 ',': ASCII/Unicode U+002C (category Po: Punctuation, other)
 '😱': Unicode U+1F631 (category So: Symbol, other)

دقت کنید که سازنده‌ی String() روی یک بردار کار می‌کند. برای تبدیل یک Char تکی به رشته‌ای یک‌نویسه‌ای، تابع string() است، با حرف کوچک s.

julia> string('a')
"a"

ذخیره‌سازی

هر چه تا اینجا در این سند گفته شد نسبتاً ساده به نظر می‌رسد، پس واقعاً چیز زیادی برای نگرانی وجود ندارد؟

متأسفانه، این بیش از حد خوش‌بینانه است!

یک پیچیدگی از اینجا می‌آید که هر کد پوینت به «حداکثر» ۶ رقم هگز نیاز دارد. یعنی نویسه‌های مختلف وقتی با UTF-8 کدگذاری می‌شوند، مقدار متفاوتی از فضای حافظه را نیاز دارند.

یک بایت فقط می‌تواند اعداد (بدون علامت) تا ۲۵۵ را ذخیره کند، یعنی دو رقم هگز، پس UTF-8 برای ذخیره‌ی یک Char از تعداد متغیری بایت (۱ تا ۴) استفاده می‌کند. به این‌ها «کد یونیت» می‌گویند و تابع ncodeunits() عدد لازم برای یک نویسه‌ی مشخص را برمی‌گرداند.

julia> codepoint(jha)  # jha 'झ' is defined in an earlier example
0x0000091d

julia> ncodeunits(jha)
3

julia> ncodeunits('a')  # ASCII character
1

julia> ncodeunits('😱')  # emoji
4

همچنین، هر چیزی که روی صفحه نمایش داده می‌شود کد پوینت یکتای خودش را ندارد. برخی نویسه‌های ظاهراً متمایز، مشتق‌شده از نویسه‌های دیگر در نظر گرفته می‌شوند، پس Unicode با آن‌ها مثل یک نویسه‌ی والد به‌همراه یک تغییردهنده برخورد می‌کند.

ویرایش از طریق GitHub این پیوند در پنجره یا زبانه‌ی جدیدی باز می‌شود

نویسه را یاد بگیرید

تمرین کردن قفل شده است

برای تمرین نویسه قفل 3 تمرین دیگر را باز کنید