نوع rune در Go نام دیگری برای int32 است.
با توجه به این نوع int32 زیربنایی، نوع rune یک مقدار صحیح ۳۲ بیتی علامتدار را نگه میدارد.
با این حال، برخلاف نوع int32، مقدار صحیح ذخیرهشده در نوع rune یک کاراکتر یونیکد را نمایش میدهد.
یونیکد یک ابرمجموعه از ASCII است که کاراکترها را با اختصاص یک عدد یکتا به هر کاراکتر نمایش میدهد. به این عدد یکتا، نقطهی کد یونیکد میگویند. یونیکد هدف دارد که همهی کاراکترهای جهان، شامل الفباهای مختلف، اعداد، نمادها و حتی ایموجیها را به صورت نقاط کد یونیکد نمایش دهد.
در Go، نوع rune یک نقطهی کد یونیکد را نمایش میدهد.
جدول زیر شامل کاراکترهای یونیکد نمونه به همراه نقطهی کد یونیکد و مقادیر اعشاری آنهاست:
| کاراکتر یونیکد | نقطهی کد یونیکد | مقدار اعشاری |
|---|---|---|
| 0 | U+0030 |
48 |
| A | U+0041 |
65 |
| a | U+0061 |
97 |
| ¿ | U+00BF |
191 |
| π | U+03C0 |
960 |
| 🧠 | U+1F9E0 |
129504 |
UTF-8 یک کدبندی کاراکتر با عرض متغیر است که برای کدبندی هر نقطهی کد یونیکد به صورت ۱، ۲، ۳ یا ۴ بایت استفاده میشود.
از آنجایی که یک نقطهی کد یونیکد میتواند حداکثر به ۴ بایت کدبندی شود، نوع rune باید بتواند تا ۴ بایت داده را نگه دارد.
به همین دلیل است که نوع rune نام دیگری برای int32 است، زیرا نوع int32 قادر است تا ۴ بایت داده را نگه دارد.
فایلهای کد منبع Go با UTF-8 کدبندی میشوند.
متغیرهای از نوع rune با قرار دادن یک کاراکتر داخل تککوتیشن اعلان میشوند:
myRune := '¿'
از آنجایی که rune فقط نام دیگری برای int32 است، چاپ نوع یک rune منجر به int32 میشود:
myRune := '¿'
fmt.Printf("myRune type: %T\n", myRune)
// Output: myRune type: int32
به طور مشابه، چاپ مقدار یک rune مقدار صحیح (اعشاری) آن را نشان میدهد:
myRune := '¿'
fmt.Printf("myRune value: %v\n", myRune)
// Output: myRune value: 191
برای چاپ کاراکتر یونیکد نمایشدادهشده توسط rune، از مشخصکنندهی قالببندی %c استفاده کنید:
myRune := '¿'
fmt.Printf("myRune Unicode character: %c\n", myRune)
// Output: myRune Unicode character: ¿
برای چاپ نقطهی کد یونیکد نمایشدادهشده توسط rune، از مشخصکنندهی قالببندی %U استفاده کنید:
myRune := '¿'
fmt.Printf("myRune Unicode code point: %U\n", myRune)
// Output: myRune Unicode code point: U+00BF
رشتهها در Go با UTF-8 کدبندی میشوند، که به این معنی است که شامل کاراکترهای یونیکد هستند. کاراکترها در رشتهها به صورت ۱، ۲، ۳ یا ۴ بایت ذخیره و کدبندی میشوند، بسته به کاراکتر یونیکدی که نمایش میدهند.
در Go، از اسلایسها برای نمایش دنبالهها استفاده میشود و این اسلایسها را میتوان با استفاده از range پیمایش کرد.
وقتی روی یک رشته پیمایش میکنیم، Go رشته را به مجموعهای از runeها تبدیل میکند که هر کدام ۴ بایت است (به یاد داشته باشید، نوع rune نام دیگری برای int32 است!)
حتی اگر یک رشته فقط یک اسلایس از بایت باشد، کلیدواژهی range روی runeهای رشته پیمایش میکند، نه بایتهای آن.
در این مثال، متغیر index نشاندهندهی اندیس شروع دنبالهی بایتی rune فعلی است و متغیر char نشاندهندهی rune فعلی است:
myString := "❗hello"
for index, char := range myString {
fmt.Printf("Index: %d\tCharacter: %c\t\tCode Point: %U\n", index, char, char)
}
// Output:
// Index: 0 Character: ❗ Code Point: U+2757
// Index: 3 Character: h Code Point: U+0068
// Index: 4 Character: e Code Point: U+0065
// Index: 5 Character: l Code Point: U+006C
// Index: 6 Character: l Code Point: U+006C
// Index: 7 Character: o Code Point: U+006F
از آنجایی که runeها میتوانند به صورت ۱، ۲، ۳ یا ۴ بایت ذخیره شوند، طول یک رشته ممکن است همیشه با تعداد کاراکترهای آن برابر نباشد.
از تابع توکار len برای گرفتن طول یک رشته بر حسب بایت و از تابع utf8.RuneCountInString برای گرفتن تعداد runeهای یک رشته استفاده کنید:
import "unicode/utf8"
myString := "❗hello"
stringLength := len(myString)
numberOfRunes := utf8.RuneCountInString(myString)
fmt.Printf("myString - Length: %d - Runes: %d\n", stringLength, numberOfRunes)
// Output: myString - Length: 8 - Runes: 6
به شما سپرده شده است که یک کتابخانهی لاگ بسازید تا در مدیریت لاگهای سازمانتان کمک کند. این کتابخانه به کاربران امکان میدهد تشخیص دهند کدام برنامه یک لاگ مشخص را تولید کرده است، لاگهای خراب را اصلاح کنند و تعیین کنند که آیا یک خط لاگ مشخص در محدودهی تعداد کاراکتر معینی قرار دارد یا نه.
لاگها از چندین برنامه میآیند که هر کدام از قالب لاگ اختصاصی خودش استفاده میکند. پیش از آنکه یک لاگ در سیستم تجمیع لاگ ذخیره شود، باید برنامهای که آن را تولید کرده است مشخص شود.
تابع Application را پیادهسازی کنید که یک خط لاگ را میگیرد و برنامهای را برمیگرداند که آن خط لاگ را تولید کرده است.
برای تشخیص اینکه کدام برنامه یک خط لاگ مشخص را تولید کرده است، خط لاگ را برای یافتن کاراکتر مشخصی که در جدول زیر آمده است جستوجو کنید:
| برنامه | کاراکتر | نقطهی کد یونیکد |
|---|---|---|
recommendation |
❗ | U+2757 |
search |
🔍 | U+1F50D |
weather |
☀ | U+2600 |
اگر یک خط لاگ هیچکدام از کاراکترهای جدول بالا را نداشته باشد، مقدار default را به فراخوانیکننده برگردانید.
اگر یک خط لاگ بیش از یک کاراکتر از جدول بالا داشته باشد، برنامهای را برگردانید که با نخستین کاراکتر یافتشده در خط لاگ، از چپ به راست، متناظر است.
Application("❗ recommended search product 🔍")
// => recommendation
به دلیل یک باگ نادر اما پایدار در زیرساخت لاگگیری، برخی کاراکترها در لاگها میتوانند خراب شوند. پس از آنکه زمانی را صرف شناسایی کاراکترهای خراب و مقدار اصلی آنها کردید، تصمیم میگیرید کتابخانهی لاگ را بهروزرسانی کنید تا در اصلاح لاگهای خراب کمک کند.
تابع Replace را پیادهسازی کنید که یک خط لاگ، یک کاراکتر خراب و مقدار اصلی را میگیرد و یک خط لاگ تغییریافته را برمیگرداند که در آن همهی موارد وقوع کاراکتر خراب با مقدار اصلی جایگزین شدهاند.
log := "please replace '👎' with '👍'"
Replace(log, '👎', '👍')
// => please replace '👍' with '👍'"
سیستمهایی که مسئول نمایش لاگها هستند، محدودیتی روی تعداد کاراکترهایی دارند که میتوان در هر خط لاگ نمایش داد. به همین دلیل، کاربران میخواهند این کتابخانه یک تابع کمکی داشته باشد تا تعیین کند آیا یک خط لاگ در محدودهی تعداد کاراکتر مشخصی قرار دارد یا نه.
تابع WithinLimit را پیادهسازی کنید که یک خط لاگ و سقف کاراکتر را میگیرد و برمیگرداند که آیا خط لاگ در محدودهی سقف کاراکتر قرار دارد یا نه.
WithinLimit("hello❗", 6)
// => true