Scanner
কিছু ক্ষেত্রে ব্যবহার করা স্ট্রিং থেকে সংখ্যাগুলি বের করার একটি খুব সুবিধাজনক উপায়। এবং এটি প্রায় ততই শক্তিশালী NumberFormatter
যখন ডিকোডিং এবং বিভিন্ন সংখ্যক ফর্ম্যাট এবং লোকালগুলি নিয়ে কাজ করার বিষয়টি আসে। এটি বিভিন্ন দশমিক এবং গোষ্ঠী বিভাজক সহ সংখ্যা এবং মুদ্রা বের করতে পারে।
import Foundation
// The code below includes manual fix for whitespaces (for French case)
let strings = ["en_US": "My salary is $9,999.99",
"fr_FR": "Mon salaire est 9 999,99€",
"de_DE": "Mein Gehalt ist 9999,99€",
"en_GB": "My salary is £9,999.99" ]
// Just for referce
let allPossibleDecimalSeparators = Set(Locale.availableIdentifiers.compactMap({ Locale(identifier: $0).decimalSeparator}))
print(allPossibleDecimalSeparators)
for str in strings {
let locale = Locale(identifier: str.key)
let valStr = str.value.filter{!($0.isWhitespace || $0 == Character(locale.groupingSeparator ?? ""))}
print("Value String", valStr)
let sc = Scanner(string: valStr)
// we could do this more reliably with `filter` as well
sc.charactersToBeSkipped = CharacterSet.decimalDigits.inverted
sc.locale = locale
print("Locale \(locale.identifier) grouping separator: |\(locale.groupingSeparator ?? "")| . Decimal separator: \(locale.decimalSeparator ?? "")")
while !(sc.isAtEnd) {
if let val = sc.scanDouble() {
print(val)
}
}
}
যাইহোক, বিভাজকদের সাথে এমন কিছু সমস্যা রয়েছে যা শব্দ সীমানা হিসাবে ধারণা করা যেতে পারে।
// This doesn't work. `Scanner` just ignores grouping separators because scanner tends to seek for multiple values
// It just refuses to ignore spaces or commas for example.
let strings = ["en_US": "$9,999.99", "fr_FR": "9999,99€", "de_DE": "9999,99€", "en_GB": "£9,999.99" ]
for str in strings {
let locale = Locale(identifier: str.key)
let sc = Scanner(string: str.value)
sc.charactersToBeSkipped = CharacterSet.decimalDigits.inverted.union(CharacterSet(charactersIn: locale.groupingSeparator ?? ""))
sc.locale = locale
print("Locale \(locale.identifier) grouping separator: \(locale.groupingSeparator ?? "") . Decimal separator: \(locale.decimalSeparator ?? "")")
while !(sc.isAtEnd) {
if let val = sc.scanDouble() {
print(val)
}
}
}
// sc.scanDouble(representation: Scanner.NumberRepresentation) could help if there were .currency case
লোকেলটি স্বয়ংক্রিয়ভাবে সনাক্ত করতে কোনও সমস্যা নেই। নোট করুন যে ফরাসি স্থানীয় লোকালগুলিতে গ্রুপিংসপেটর স্ট্রিং "সোম বেতন ইস্ট 9999,99 €" স্ট্রিং নয়, যদিও এটি স্থান হিসাবে ঠিক রেন্ডার হতে পারে (এখানে এটি তা দেয় না)। নীচের কোডটি !$0.isWhitespace
চরিত্রগুলি ছাঁটা না করে কেন সূক্ষ্মভাবে কাজ করে তা ঠিক ts
let stringsArr = ["My salary is $9,999.99",
"Mon salaire est 9 999,99€",
"Mein Gehalt ist 9.999,99€",
"My salary is £9,999.99" ]
let tagger = NSLinguisticTagger(tagSchemes: [.language], options: Int(NSLinguisticTagger.Options.init().rawValue))
for str in stringsArr {
tagger.string = str
let locale = Locale(identifier: tagger.dominantLanguage ?? "en")
let valStr = str.filter{!($0 == Character(locale.groupingSeparator ?? ""))}
print("Value String", valStr)
let sc = Scanner(string: valStr)
// we could do this more reliably with `filter` as well
sc.charactersToBeSkipped = CharacterSet.decimalDigits.inverted
sc.locale = locale
print("Locale \(locale.identifier) grouping separator: |\(locale.groupingSeparator ?? "")| . Decimal separator: \(locale.decimalSeparator ?? "")")
while !(sc.isAtEnd) {
if let val = sc.scanDouble() {
print(val)
}
}
}
// Also will fail if groupingSeparator == decimalSeparator (but don't think it's possible)