۱۰ اکستنشن رشته ای مفید کاتلین — به زبان ساده
کاتلین یک زبان برنامهنویسی نسبتاً جدید محسوب میشود. این زبان بر مبنای جاوا ساخته شده است و کد کاتلین روی JVM کار میکند. کد کاتلین میتواند به صورت اپلیکیشنهای نیتیو (Kotlin Native) و اپلیکیشنهای نیتیو جاوا اسکریپت ( Kotlin JS) کامپایل شود. در این مقاله با 10 اکستنشن رشته ای مفید کاتلین آشنا خواهیم شد.
گوگل در سال 2017 کاتلین را به عنوان زبان رسمی برای توسعه اندروید معرفی کرد. در سال 2019 اعلام شد که اندروید یک پلتفرم Kotlin-first است. اما چرا کاتلین بهتر از جاوا است؟
- کاتلین از optional-ها پشتیبانی میکند. Optional-ها به جلوگیری از بروز کرش کمک میکنند.
- کاتلین منسجمتر است. هسته آن کوچکتر است، خواناییاش بالاتر است و نگهداری آن آسانتر محسوب میشود.
- کاتلین از اکستنشنها پشتیبانی میکند.
در این مقاله به توضیح اکستنشنهای رشتهای میپردازیم که موجب کوتاهتر، امنتر و بهبود کلی کد میشوند.
اکستنشنهای رشتهای در نسخه 1.3.7.0 کاتلین معرفی شدهاند، اما با نسخههای دیگر نیز سازگار هستند. این اکستنشنها که در این مقاله معرفی خواهیم کرد، در محیط Kotlin/Native و Kotlin/JS نیز کار میکنند.
1. محاسبهگر هش MD5/SHA
شاید از خود بپرسید چه لزومی به محاسبه MD5 یک رشته وجود دارد؟ این کار به دلایل مختلفی ممکن است لازم باشد. برای نمونه ممکن است بخواهید یک رمز عبور را در پایگاه داده ذخیره کنید، یا برخی تغییرها از طریق یک کانال غیر امن اجرا کنید و یا بررسی کنید آیا یک فایل به درستی محاسبه شده یا نه. همین موضوع در مورد هشهای SHA نیز صدق میکند.
کار خود را با MD5 آغاز میکنیم:
1import java.security.MessageDigest
2
3val String.md5: String
4get() {
5 val bytes = MessageDigest.getInstance("MD5").digest(this.toByteArray())
6 return bytes.joinToString("") {
7 "%02x".format(it)
8 }
9}
md5 یک مشخصه محاسبهشده دارد. ابتدا از java.security.MessageDigest برای محاسبه هش MD5 به صورت آرایه بایتی استفاده میکنیم. سپس آرایه بایتی را به رشته hex تبدیل میکنیم.
SHA-1 اختصاری برای عبارت «الگوریتم هش امن -1» (Secure Hash Algorithm — 1) است. به طور کلی SHA به گروهی از الگوریتمها گفته میشود. تفاوتی بین آنها از نظر برنامهنویسی وجود ندارد و تنها نام الگوریتم در فراخوانی ()MessageDigest.getInstance عوض میشود:
1import java.security.MessageDigest
2
3val String.sha1: String
4get() {
5 val bytes = MessageDigest.getInstance("SHA-1").digest(this.toByteArray())
6 return bytes.joinToString("") {
7 "%02x".format(it)
8 }
9}
شیوه استفاده
برای استفاده از این محاسبهگرهای هش از کدی مانند زیر استفاده میکنیم:
1val md5Hash = "test".md5 // 098f6bcd4621d373cade4e832627b4f6
2val sha1Hash = "test".sha1 // a94a8fe5ccb19ba61c4c0873d391e987982fbbd3
2. بررسی این که یک رشته، نشانی ایمیل معتبری باشد
بررسی اعتبارسنجی یک نشانی ایمیل قابلیت بسیار رایجی محسوب میشود. تقریباً اغلب اپلیکیشنهای اندروید کاربر را ملزم به ثبت نام میکنند. اغلب آنها هم از روش ثبت نام با ایمیل و رمز عبور استفاده میکنند. بنابراین بهتر است که نشانی ایمیل وارد شده از سوی کاربر را پیش از ارسال به سرور و به هدر دادن پهنای باند و تحویل یک فراخوانی ثبت نام/ورود ناموفق، در خود اپلیکیشن مورد اعتبارسنجی قرار دهیم. اگر یک توسعهدهنده بکاند باشید، اعتبارسنجی نشانی ایمیل پیش از ذخیره آن در پایگاه داده اهمیتی حیاتی دارد.
سادهترین روش برای اعتبارسنجی یک ایمیل، استفاده از «عبارتهای منظم» (regular expressions) است.. بسته به نیازهایتان میتوانید یک عبارت منظم تهیه کنید. ما استفاده از عبارت منظم زیر را پیشنهاد میکنیم:
1import java.util.regex.Pattern
2
3fun String.isEmailValid(): Boolean {
4 val expression = "^[\\w.-]+@([\\w\\-]+\\.)+[A-Z]{2,8}$"
5 val pattern = Pattern.compile(expression, Pattern.CASE_INSENSITIVE)
6 val matcher = pattern.matcher(this)
7 return matcher.matches()
8}
این عبارت یک تابع ارائه میکند، اما مشخصه محاسبهشده نیز یک گزینه محسوب میشود.
شیوه استفاده
برای استفاده از عبارت منظم فوق جهت اعتبارسنجی نشانی ایمیل میتوانید به صورت زیر عمل کنید:
1val email = "test@email.com"
2if (email.isEmailValid()) {
3 print("Email is valid. Continue registration")
4} else {
5 print("Email is not validate. Show error")
6}
3. اعتبارسنجی و قالببندی شماره تلفن
شماره تلفن نیز همانند ایمیل یک روش متداول برای ثبت نام کاربر است که باید اعتبار سنجی شود و بررسی قالببندی آن شاید حتی اهمیت بیشتری داشته باشد. شماره تلفن تنها بر حسب شماره کد کشور یکتا است، اما کاربران معمولاً کد کشور را وارد نمیکنند، چون غالباً از روش وارد کردن نام کشور یا تعیین پرچم آن استفاده میکنند. بنابراین این روش متفاوت از ایمیل است.
همچنین شمارههای تلفن کشورهای مختلف، قالببندیهای متفاوتی دارند. به همین جهت است که برای انجام این کار به یک کتابخانه اکسترنال نیاز داریم.
برای کد JVM یک کتابخانه از سوی گوگل به نام libphonenumber ارائه شده است. برای اندروید یک نسخه خاص از آن به نام libphonenumber-android وجود دارد که تقریباً مشابه نسخه اصلی است.
نسخه JVM
1import com.google.i18n.phonenumbers.PhoneNumberUtil
2
3fun String.formatPhoneNumber(region: String): String? {
4 val phoneNumberKit = PhoneNumberUtil.getInstance()
5 val number = phoneNumberKit.parse(this, region)
6 if (!phoneNumberKit.isValidNumber(number))
7 return null
8
9 return phoneNumberKit.format(number, PhoneNumberUtil.PhoneNumberFormat.INTERNATIONAL)
10}
این تابع یک شماره تلفن قالببندیشده بازگشت میدهد که با علامت + آغاز میشود و سپس کد کشور میآید اگر اپلیکیشن صرفاً برای یک کشور عرضه شده باشد، میتوان این مقدار را هاردکد کرد.
شیوه استفاده
در کد زیر روش استفاده از این کتابخانه نمایش یافته است:
1val phone = "(202)555-0156" // Phone number is fake, but has valid format
2val formattedPhone = phone.formatPhoneNumber("US")
3if (formattedPhone == null) {
4 println("Phone number is not valid")
5} else {
6 println("Sending $formattedPhone to API")
7}
نسخه اندروید
1import android.content.Context
2import io.michaelrocks.libphonenumber.android.PhoneNumberUtil
3
4fun String.formatPhoneNumber(context: Context, region: String): String? {
5 val phoneNumberKit = PhoneNumberUtil.createInstance(context)
6 val number = phoneNumberKit.parse(this, region)
7 if (!phoneNumberKit.isValidNumber(number))
8 return null
9
10 return phoneNumberKit.format(number, PhoneNumberUtil.PhoneNumberFormat.INTERNATIONAL)
11}
این تابع در صورتی که شماره تلفن معتبر باشد، آن شماره تلفن قالببندیشده را با علامت بعلاوه و کد کشور آغاز میشود، بازگشت میدهد. در غیر این صورت مقدار nill بازگشت خواهد یافت. آرگومان نخست Context اندروید برای مثال Activity است.
شیوه استفاده
در کد زیر روش استفاده از کتابخانه فوق را در کد اندروید میبینید:
1val phone = "(202)555-0156" // Phone number is fake, but has valid format
2val formattedPhone = phone.formatPhoneNumber(this, "US")
3if (formattedPhone == null) {
4 println("Phone number is not valid")
5} else {
6 println("Sending $formattedPhone to API")
7}
4. بررسی موارد داخلی
شاید برایتان پیش آمده باشد که بخواهید بدانید داخل یک رشته چیست؟ برای مثال آیا داخل رشته، یک عدد، یک کلمه یا یک رمز عبور با کاراکترهای خاص قرار دارد. برخی اوقات برای این که بدانیم در ادامه باید چه کار کنیم باید ابتدا این اطلاعات را در اختیار داشته باشیم. به این منظور یک اکستنشن مینویسیم:
1val String.containsLatinLetter: Boolean
2 get() = matches(Regex(".*[A-Za-z].*"))
3
4val String.containsDigit: Boolean
5 get() = matches(Regex(".*[0-9].*"))
6
7val String.isAlphanumeric: Boolean
8 get() = matches(Regex("[A-Za-z0-9]*"))
9
10val String.hasLettersAndDigits: Boolean
11 get() = containsLatinLetter && containsDigit
12
13val String.isIntegerNumber: Boolean
14 get() = toIntOrNull() != null
15
16val String.toDecimalNumber: Boolean
17 get() = toDoubleOrNull() != null
شیوه استفاده
در مثال زیر روش استفاده از این اکستنشن را میبینید:
1val cl = "Contains letters".containsLatinLetter // true
2val cnl = "12345".containsLatinLetter // false
3val cd = "Contains digits 123".containsDigit // true
4val istr = "123".isIntegerNumber // true
5val dstr = "12.9".toDecimalNumber // true
فرض کنید میخواهیم بررسی کنیم آیا یک رمز عبور معتبر است یا نه. این کار در مورد تعیین رمزهای عبور جدید ضروری است. رمز عبور جدید باید یک رقم، یک حرف لاتین و یک کاراکتر غیر حرف و عدد داشته باشد. ضمناً نباید فاصله به جز در مورد کاراکترهای اول و آخر داشته باشد، چون این موارد را میتوانیم حذف کنیم. آخرین الزام اعتبارسنجی، طول رمز عبور است که باید بین شش تا 20 کاراکتر باشد.
در این حالت از کد زیر استفاده میکنیم:
1val password = "yt6Hbb2.s(ma**213"
2val password2 = "yt6Hbb2sma213"
3val isPasswordValid = !password.isAlphanumeric && password.containsDigit && password.containsLatinLetter && password.length > 6 && password.length < 20 // true
4val isPassword2Valid = !password2.isAlphanumeric && password2.containsDigit && password2.containsLatinLetter && password2.length > 6 && password2.length < 20 // false, doesn't contain non-alphanumeric characters
5. ذخیرهسازی و بازیابی تنظیمات لوکال
این اکستنشن خاص اندروید است. کاتلین یک زبان رسمی برای توسعه اندروید محسوب میشود. امروزه اغلب اپلیکیشنهای پلی استور از کاتلین استفاده میکنند. زمان توسعه کوتاهتر شده و کیفیت افزایش یافته و همزمان سازگاری و تفسیرپذیری کاملی با جاوا دارد. اپلیکیشنهای اندرویدی چند روش برای ذخیرهسازی تنظیمات لوکال دارند، اما سادهترین روش استفاده از SharedPreferences است:
1import android.annotation.SuppressLint
2import android.content.Context
3
4@SuppressLint("ApplySharedPref")
5fun String.save(applicationContext: Context, value: Map<String, Any>, clear: Boolean = false, now: Boolean = false) {
6 val sp = applicationContext.getSharedPreferences(this, Context.MODE_PRIVATE).edit()
7 if (clear)
8 sp.clear()
9 value.keys.forEach { key ->
10 val v = value[key]
11 if (v != null) {
12 when (v) {
13 is String -> sp.putString(key, v)
14 is Float -> sp.putFloat(key, v)
15 is Long -> sp.putLong(key, v)
16 is Int -> sp.putInt(key, v)
17 is Boolean -> sp.putBoolean(key, v)
18 }
19 }
20 }
21 if (now)
22 sp.commit()
23 else
24 sp.apply()
25}
26
27fun String.load(applicationContext: Context): Map<String, Any> {
28 val sp = applicationContext.getSharedPreferences(this, Context.MODE_PRIVATE)
29 val keys = sp.all.keys
30 val result = hashMapOf<String, Any>()
31 keys.map { key ->
32 val v = sp.all[key]
33 if (v != null)
34 result[key] = v
35 }
36 return result
37}
آرگومان نخست applicationContext: Context است. اگر تابع را از Activity اجرا کنید، خودش را و شاید بهتر از آن applicationContext ارسال میکند. آرگومان دوم value: Map<String, Any> است. مپها در کاتلین به سادگی ایجاد شده و به آسانی استفاده میشوند. در این اکستنشن Any میتواند یک مقدار غیر تهی داشته باشد، اما تنها پنج نوع Int, Float, Long, Boolean و String ذخیره میشوند.
در صورتی که همه فیلدهای SharedPreferences که در value نیستند را بخواهیم از SharedPreferences پاک کنیم، آرگومان clear باید مقدار true داشته باشد. نکته دیگر در مورد SharedPreferences به ذخیرهسازی پسزمینه مربوط است. دو روش برای ذخیره به صورتهای SharedPreferences: commit و apply وجود دارند. تفاوت در این است که commit تغییرها را بیدرنگ اعمال میکند، اما ذخیره بیدرنگ را تضمین نمیکند. در اغلب موارد بهتر است از apply استفاده کنید، به همین دلایل است که آرگومان now باید تقریباً همیشه مقدار false داشته باشد.
شیوه استفاده
در مثال زیر شیوه استفاده از این اکستنشن برای ذخیرهسازی تنظیمات یک بازی را میبینید:
1"com.app.options".save(applicationContext,
2 mapOf(
3 "volume" to 0.8f,
4 "fullscreen" to true
5 )
6)
7
8val volume = "options".load(applicationContext)["volume"] as? Float // 0.8
توجه کنید که در کد فوق SharedPreferences با apply ذخیره شده است. همزمان میتوان بیدرنگ از آن استفاده کرد. دلیل این امر آن است که SharedPreferences در حافظه گوشی ذخیره میشود. اگر اپلیکیشن در همین لحظه کرش کند؛، این احتمال به خصوص در مواردی که مقدار حجیمی باشد، وجود دارد که مقدار ذخیره نشده باشد.
6. تجزیه JSON از یک رشته
جاوا و کاتلین امکان تجزیه یک JSON را به صورت کلاسهای JSONObject یا JSONArray فراهم ساختهاند.
در این بخش یک ویرایش جزئی روی اینها انجام میدهیم تا سریعتر و بدون استثنا کار کنند. اگر string شامل یک JSON معتبر باشد، تابع زیر JSONObject یا JSONArray و در غیر این صورت مقدار null بازگشت میدهد.
1import org.json.JSONArray
2import org.json.JSONException
3import org.json.JSONObject
4
5val String.jsonObject: JSONObject?
6 get() = try {
7 JSONObject(this)
8 } catch (e: JSONException) {
9 null
10 }
11
12val String.jsonArray: JSONArray?
13 get() = try {
14 JSONArray(this)
15 } catch (e: JSONException) {
16 null
17 }
شیوه استفاده
در مثال زیر روش تجزیه یک رشته JSON و تبدیل مجدد آن به Striong را میبینید:
1val json = "{\"key\": \"value\"}".jsonObject // {"key": "value"}
2val jsonAgain = json?.toString() // "{"key": "value"}"
3val stringFromJson = json?.getString("key") // "value"
7. کامپوننت آخرین مسیر
Apple Foundation یک مشخصه بسیار مفید به نام lastPathComponent دارد. اگر String شامل یک مسیر یا URL باشد، کامپوننت آخر (یعنی پس از /) بازگشت مییابد. در این بخش این قابلیت را در کاتلین ایجاد میکنیم:
اما قبل از آن باید دو نکته را مورد اشاره قرار دهیم:
- مسیر میتواند با اسلش پایانی خاتمه یابد. تابع اکستنشن باید کامپوننت مسیر قبل از آن را بازگشت دهد، چون در غیر این صورت URL-ها پردازش نمیشوند.
- برخی سیستمها (مانند ویندوز مایکروسافت) به جای اسلش از بکاسلش استفاده میکنند. این مورد را نیز باید مدیریت کنیم:
1val String.lastPathComponent: String
2get() {
3 var path = this
4 if (path.endsWith("/"))
5 path = path.substring(0, path.length - 1)
6 var index = path.lastIndexOf('/')
7 if (index < 0) {
8 if (path.endsWith("\\"))
9 path = path.substring(0, path.length - 1)
10 index = path.lastIndexOf('\\')
11 if (index < 0)
12 return path
13 }
14 return path.substring(index + 1)
15}
شیوه استفاده
در مثال زیر روش استفاده از این اکستنشن را میبینید:
1val lpc1 = "https://google.com/chrome/".lastPathComponent // chrome
2val lpc2 = "C:\\Windows\\Fonts\\font.ttf".lastPathComponent // font.ttf
3val lpc3 = "/dev/null".lastPathComponent // null
8. استخراج رنگ از رشته
رنگ در محیطهای مختلف به روش متفاوتی نمایش مییابد. اندروید از اعداد صحیح ساده استفاده میکند. اندروید یک کلاس Color دارد، اما این کلاس صرفاً شامل تابعهای کمکی است. بازنمایی رنگ، دیگر کلاس Color مربوط به AWT است که چهار مقدار صحیح را برای اجزای قرمز، سبز، آبی و آلفای رنگها شامل میشود.
تجزیه رشته hex به رنگ AWT
1import java.awt.Color
2
3val String.awtColor: Color?
4get() {
5 val r = substring(1, 3).toIntOrNull(16) ?: return null
6 val g = substring(3, 5).toIntOrNull(16) ?: return null
7 val b = substring(5, 7).toIntOrNull(16) ?: return null
8 return Color(r, g, b)
9}
شیوه استفاده
در مثال زیر روش استفاده از این اکستنشن توضیح داده شده است:
1val c = "#010203".awtColor
2print(c.toString()) // java.awt.Color[r=1,g=2,b=3]
تجزیه رشته به رنگ Android
1import android.graphics.Color
2
3val String.asColor: Int?
4 get() = try {
5 Color.parseColor(this)
6 } catch (e: java.lang.IllegalArgumentException) {
7 null
8 }
این کلاس یک Int بازگشت میدهد، زیرا اندروید در نماهای خود از مقادیر Int استفاده میکند.
شیوه استفاده
1val colorHex = "#010203"
2val color = colorHex.asColor // -16711165
3val nonColorHex = "abcdef"
4val nonColor = nonColorHex.asColor // null
ممکن است بپرسید حال که قرار است یک خط کد را با خط دیگری جایگزین کنیم، چرا باید از اکستنشن استفاده کنیم؟ به مثال زیر توجه کنید:
1val color1 = Color.parseColor(hexString)
2val color2 = hexString.asColor
دو تفاوت وجود دارد:
- اکستنشن asColor میتواند به صورت زنجیرهای برای مثال مانند زیر مورد استفاده قرار گیرد:
()hexString.asColor?.toString - به جای استثنا از null استفاده میکنیم. دیگر لازم نیست از بلوک try-catch استفاده کنید، چون در صورتی که مقدار رنگ معتبر نباشد، صرفاً مقدار null ارائه میشود.
9. قالببندی رشته به صورت شماره کارت بانکی
برخی اپلیکیشنهای اندرویدی محصولها یا سرویسهایی را میفروشند که امکان فروش به صورت خرید درونبرنامهای ندارند. سرور اپ استور برای جاوا اقدام به استفاده و نمایش شماره کارت بانکی به کاربر میکند. به طور معمول اپلیکیشنها این شماره کارت بانکی را به صورت String بدون فاصله ذخیره میکنند. اما خواندن یک شماره 16 رقمی بدون جداسازی ارقام برای کاربران آسان نیست. یک اکستنشن ساده میتواند پس از هر چهار کاراکتر رشته یک فاصل اضافه کند:
1val String.creditCardFormatted: String
2get() {
3 val preparedString = replace(" ", "").trim()
4 val result = StringBuilder()
5 for (i in preparedString.indices) {
6 if (i % 4 == 0 && i != 0) {
7 result.append(" ")
8 }
9 result.append(preparedString[i])
10 }
11 return result.toString()
12}
شیوه استفاده
در مثال زیر روش استفاده از این اکستنشن را میبینید:
1val ccFormatted = "1234567890123456".creditCardFormatted // "1234 5678 9012 3456"
10. کار امن با JSON
JSON و XML دو قالب رایج برای بارگذاری، ذخیره و تبادل دادهها هستند. تصور فراخوانی یک API بدون استفاده از این قالبها کار دشواری است. جاوا کلاسهای نسبتاً خوبی برای کار با این قالبها ارائه کرده است که شامل JSONObject و JSONArray میشود. کاتلین میتواند از هر کلاس جاوا استفاده کند، بنابراین روش کاتلین برای تجزیه و نوشتن JSON نیز چنین است. JSONObject و JSONArray روی اندروید در اختیار ما هستند.
شاید بپرسید چرا باید این کلاس را بسط دهیم؟ مشکل اینجا است که این کلاسها، اگر چیزی نادرست باشد، یک استثنا ایجاد میکنند. برای نمونه اگر تلاش کنید نوع داده نادرستی را به دست آورید، یا اگر به فیلدی که وجود ندارد، ارجاع دهید، چنین مشکلی پیش میآید.
1try {
2 val obj = JSONObject()
3 obj.put("str", "abc")
4 val strAsInt = obj.getInt("str") // org.json.JSONException: Value abc at str of type java.lang.String cannot be converted to int
5val noKey = obj.getString("iamnothere") // org.json.JSONException: No value for iamnothere
6} catch (e: JSONException) {
7 e.printStackTrace()
8}
البته استثناها ذاتاً مشکلی ندارند. استثنا یک روش خوب برای مدریت چنین موقعیتهایی محسوب میشود. اما گاهی اوقات لازم است که تنها فیلدهای موجود را به دست آوریم و فیلدهایی که در پاسخ API وجود ندارند را نادیده بگیریم. بدون استفاده از اکستنشن این کار به صورت زیر انجام مییابد:
1val firstName: String?
2try {
3 firstName = json.getString("first_name")
4} catch (e: JSONException) {
5 firstName = null
6}
7val lastName: String?
8try {
9 lastName = json.getString("last_name")
10} catch (e: JSONException) {
11 lastName = null
12}
چنان که میبینید کدی طولانی است. اکنون تصور کنید سرور به جای null مقدار "null" بازگشت دهد. کد برای هر فیلد افزایش مییابد.
این موقعیت با استفاده از یک اکستنشن مانند زیر حل میشود:
1import org.json.JSONArray
2import org.json.JSONException
3import org.json.JSONObject
4
5fun JSONObject.getIntOrNull(name: String): Int? =
6 try {
7 getInt(name)
8 }
9 catch (e: JSONException) {
10 val strValue = getStringOrNull(name)
11 strValue?.toIntOrNull()
12 }
13
14fun JSONObject.getDoubleOrNull(name: String): Double? =
15 try {
16 getDouble(name)
17 }
18 catch (e: JSONException) {
19 null
20 }
21
22fun JSONObject.getLongOrNull(name: String): Long? =
23 try {
24 getLong(name)
25 }
26 catch (e: JSONException) {
27 null
28 }
29
30fun JSONObject.getStringOrNull(name: String): String? =
31 try {
32 getString(name).trim()
33 }
34 catch (e: JSONException) {
35 null
36 }
37
38fun JSONObject.getBooleanOrNull(name: String): Boolean? =
39 try {
40 getBoolean(name)
41 }
42 catch (e: JSONException) {
43 null
44 }
45
46fun JSONObject.getObjectOrNull(name: String): JSONObject? =
47 try {
48 getJSONObject(name)
49 }
50 catch (e: JSONException) {
51 null
52 }
53
54fun JSONObject.getArrayOrNull(name: String): JSONArray? =
55 try {
56 getJSONArray(name)
57 }
58 catch (e: JSONException) {
59 null
60 }
61
62fun JSONObject.getArrayOrEmpty(name: String): JSONArray =
63 try {
64 getJSONArray(name)
65 }
66 catch (e: JSONException) {
67 JSONArray()
68 }
این اکستنشن برخی قابلیتهای جانبی مانند حذف فاصلههای ابتدایی و انتهایی رشتهها را نیز دارد. بهتر است این اکستنشن را قبل از کپی کردن به پروژه به دقت بررسی کنید. قابلیتهای مانند جایگزینی "null" به جای null را میتوان به صورت زیر اضافه کرد:
1fun JSONObject.getStringOrNull(name: String): String? =
2 try {
3 val str = getString(name).trim()
4 if (str == "null") return null
5 return str
6 }
7 catch (e: JSONException) {
8 null
9 }
شیوه استفاده
1val firstName = json.getStringOrNull("first_name")
2val lastName = json.getStringOrNull("last_name")
نکته: یک روش جایگزین برای تجزیه JSON، استفاده از کتابخانههای اکسترنال مانند GSON یا Moshi است.
سخن پایانی
شما چه یک توسعهدهنده JVM، توسعهدهنده اندروید و یا توسعهدهنده کاتلین نیتیو باشد، در هر حال مطالبی که در این راهنما در خصوص اکستنشنهای رشتهای کاتلین ارائه شد، برای شما مفید خواهند بود.
اگر این مطلب برای شما مفید بوده است، آموزشهای زیر نیز به شما پیشنهاد میشوند:
- مجموعه آموزشهای برنامهنویسی
- آموزش مقدماتی زبان برنامه نویسی کاتلین (Kotlin) برای توسعه اندروید (Android)
- مجموعه آموزشهای برنامهنویسی اندروید
- زبان برنامه نویسی کاتلین (Kotlin) — راهنمای کاربردی
- کلاس inline در کاتلین — از صفر تا صد
==