I got homework and I can't handle it. What I need?
I have a project that uses two languages (English, Spanish). The project has 2 Locolizable.strings files for two languages.
Example string:
"OrderDetails_IPText" = "IP: %#";
I understand %# is a string or some object, it does not matter. The problem is in people who help me with the translation of texts into different languages.
When they fill in the translation file, they see:
%#
They do not understand what I want to add there. This could be an email address or something else. People who translate the text gave me the task to implement a function that will take into account such nuances. They even offered some implementation, something like this:
func pffffff(format: something, ["key" : value] -> Id : value
Probably it should be an extension for String.
If you do not understand, thanks for watching this question. I did not understand anything.
We advised that you need to change this func:
func L (_ key: String, value: String = "") -> String
{
let str = NSLocalizedString(key, value: value, comment: "")
return str
}
You can create something like this.
extension String {
func yourFunction () {}
}
But I would recommend you not to use %# or any other character in localization string. You can always use replace string function with when the string contains any variable
For eg:
"We have sent an OTP at [VARIABLEA]"
Then while displaying just look for [VARIABLEA] and replace with actual value
I found a way out of this situation.
public extension String {
/* Creates the string representation of the poo with requested size.
- parameter format: string format with key
- returns: localizable string
*/
public init(format: String, keyArguments: [String: Any]) {
self = format
keyArguments.forEach {
self = self.replacingOccurrences(of: "{\($0.key)}", with: "\($0.value)", options: .caseInsensitive)
}
}
}
Was:
let asd = String(format: "Hi, %#! %d", "Arnold", 2)
Now:
let str = String(format: "Hi, {User_Name}! How are you, {user_name}?", keyArguments: ["user_name" : "Arnold", "number": 5.6])
Related
I have a function I use to generate random strings for email addresses or passwords (for example). It was originally set like this:
static func random(length: Int) -> String {
let characters = "abcdefghijklmnopqrstuvwxyz"
return String((0..<length).map { _ in characters.randomElement()! })
}
So I changed it to this:
static func random(length: Int) -> String {
let characters = CharacterSet.lowercaseLetters
return String((0..<length).map { _ in characters.randomElement()! })
}
But I get an error saying "Value of type 'CharacterSet' has no member 'randomElement'.
I'm very new to Swift and I've done a lot of searching and so far I haven't found a good solution. I want to keep this function short and sweet. And I've been at this for a while now. Any help would be greatly appreciated! Please let me know if any more context is needed.
Edit: My question got closed because it was seen as a duplicate but, I looked at the solution page and tried to apply it to my issue and still no resolution. I'm not sure if that's because the previous answers are from 2015 and older or they were for obj-c
As I said in my comment of the possible duplicated post you can use that extension from the accepted answer to get all characters from a CharacterSet and get a randomElement from the resulting collection. Also as stated in the accepted answer some characters may not be present in the font used to display the result:
extension CharacterSet {
var array: [Character] {
var result: [Character] = []
for plane: UInt8 in 0...16 where hasMember(inPlane: plane) {
for unicode in UInt32(plane) << 16 ..< UInt32(plane + 1) << 16 {
if let uniChar = UnicodeScalar(unicode), contains(uniChar) {
result.append(Character(uniChar))
}
}
}
return result
}
}
let lowercaseLettersArray = CharacterSet.lowercaseLetters.array
let randomCharacter = lowercaseLettersArray.randomElement()! // "ᵳ"
I accept from backend the following json
{
"id": "f33919f6-3554-4246-9e78-bca3a690c119",
"title": "Category3",
"slug": "category3",
"hex_up": "#eb4034",
"hex_down": "#80302a",
"emoji": "U+1F602",
"parent_id": "aa3f651b-f068-4ae1-a9d8-a18a9945b111"
}
There is a field "emoji": "U+1F602",
I need show emoji icon like 😃 in UILabel
I tried to google and found results like
let scalarValue = UnicodeScalar(emojiString)
let myString = String(scalarValue!)
Unfortunately app crashes at the second line.
Thanks for your answers.
There's no U+... syntax in Swift. (There is a \u{...} syntax that does the same thing, but it's not necessary here.)
You'll need to parse the String yourself:
func parseUnicode(_ string: String) -> String? {
guard string.hasPrefix("U+"), // Make sure it's a U+ string
let value = Int(string.dropFirst(2), radix: 16), // Convert to Int
let scalar = UnicodeScalar(value) // Convert to UnicodeScalar
else { return nil }
return String(scalar) // Convert to String
}
if let myString = parseUnicode(emoji) { ... }
Don't use ! here. The U+... string may be invalid, and you wouldn't want to crash in that case.
You can simply apply a string transform from "Hex/Unicode" to "Any" (a set of all characters):
"U+1F602".applyingTransform(.init("Hex/Unicode-Any"), reverse: false) // "😂"
or as instance properties of StringProtocol to encode/decode from/to hexa unicode:
extension StringTransform {
static let unicodeToAny: Self = .init("Hex/Unicode-Any")
static let anyToUnicode: Self = .init("Any-Hex/Unicode")
}
extension StringProtocol {
var decodingHexaUnicode: String {
applyingTransform(.unicodeToAny, reverse: false)!
}
var encodingHexaUnicode: String {
applyingTransform(.anyToUnicode, reverse: false)!
}
}
Usage:
let hexaUnicode = "U+1F602"
let emoji = hexaUnicode.decodingHexaUnicode // "😂"
let unicodeFromEmoji = emoji.encodingHexaUnicode // "U+1F602"
The reason your app crashed is due to the fact that the scalarValue you attempted to initialize is nil, and you're force-unwrapping using (!) that nil value on line 2. Rob's answer shows how to unwrap the optional safely.
You can get the emoji by using the value following the U+. So you'll need to drop the first two characters of the string. So use this code to accomplish that:
let parsedEmoji = emojiString.substring(from:2)
Now you'll convert that emoji unicode using the code below.
let emoji = String(UnicodeScalar(Int(parsedEmojiHex,radix: 16)!)!)
print(emoji)
I searched over web pages and stack overflow about validation of a Persian(Farsi) language string. Most of them have mentioned Arabic letters. Also, I want to know if my string is fully Persian(not contain).
for example, these strings are Persian:
"چهار راه"
"خیابان."
And These are not:
"خیابان 5"
"چرا copy کردی؟"
Also, just Persian or Arabic digits are allowed. There are exceptions about [.,-!] characters(because keyboards are not supported these characters in Persian)
UPDATE:
I explained a swift version of using regex and predicate in my answer.
Based on this extension found elsewhere:
extension String {
func matches(_ regex: String) -> Bool {
return self.range(of: regex, options: .regularExpression, range: nil, locale: nil) != nil
}
}
and construct your regex containing allowed characters like
let mystra = "چهار راه"
let mystrb = "خیابان."
let mystrc = "خیابان 5"
let mystrd = "چرا copy کردی؟" //and so on
for a in mystra {
if String(a).matches("[\u{600}-\u{6FF}\u{064b}\u{064d}\u{064c}\u{064e}\u{064f}\u{0650}\u{0651}\u{0020}]") { // add unicode for dot, comma, and other needed puctuation marks, for now I added space etc
} else { // not in range
print("oh no--\(a)---zzzz")
break // or return false
}
}
Make sure you construct the Unicode needed using the above model.
Result for other strings
for a in mystrb ... etc
oh no--.---zzzz
oh no--5---zzzz
oh no--c---zzzz
Enjoy
After a period I could find a better way:
extension String {
var isPersian: Bool {
let predicate = NSPredicate(format: "SELF MATCHES %#",
"([-.]*\\s*[-.]*\\p{Arabic}*[-.]*\\s*)*[-.]*")
return predicate.evaluate(with: self)
}
}
and you can use like this:
print("yourString".isPersian) //response: true or false
The main key is using regex and predicate. these links help you to manipulate whatever you want:
https://nshipster.com/nspredicate/
https://nspredicate.xyz/
http://userguide.icu-project.org/strings/regexp
Feel free and ask whatever question about this topic :D
[EDIT] The following regex can be used to accept Latin numerics, as they are mostly accepted in Persian texts
"([-.]*\\s*[-.]*\\p{Arabic}*[0-9]*[-.]*\\s*)*[-.]*"
I want to check whether my filename with just prefix is exist or not in Swift.
E.g
My file name is like Companies_12344
So after _ values are dynamic but "Companies_" is static.
How can i do that?
My code below For split
func splitFilename(str: String) -> (name: String, ext: String)? {
if let rDotIdx = find(reverse(str), "_")
{
let dotIdx = advance(str.endIndex, -rDotIdx)
let fname = str[str.startIndex..<advance(dotIdx, -1)]
println("splitFilename >> Split File Name >>\(fname)")
}
return nil
}
It's not very clear what you want to do, because your code snippet already does check if the string has the prefix.
There's a simpler way, though:
let fileName = "Companies_12344"
if fileName.hasPrefix("Companies") {
println("Yes, this one has 'Companies' as a prefix")
}
Swift's hasPrefix method checks if the string begins with the specified string.
Also, you could split the string easily with this:
let compos = fileName.componentsSeparatedByString("_") // ["Companies", "12344"]
Then you could check if there's a code and grab it with:
if let fileCode = compos.last {
println("There was a code after the prefix: \(fileCode)")
}
I can't figure out how to load a string from a file and have variables referenced in that string be interpolated.
Let's say a text file at filePath that has these contents:
Hello there, \(name)!
I can load this file into a string with:
let string = String.stringWithContentsOfFile(filePath, encoding: NSUTF8StringEncoding, error: nil)!
In my class, I have loaded a name in: let name = "George"
I'd like this new string to interpolate the \(name) using my constant, so that its value is Hello there, George!. (In reality the text file is a much larger template with lots of strings that need to be swapped in.)
I see String has a convertFromStringInterpolation method but I can't figure out if that's the right way to do this. Does anyone have any ideas?
This cannot be done as you intend, because it goes against type safety at compile time (the compiler cannot check type safety on the variables that you are trying to refer to on the string file).
As a workaround, you can manually define a replacement table, as follows:
// Extend String to conform to the Printable protocol
extension String: Printable
{
public var description: String { return self }
}
var string = "Hello there, [firstName] [lastName]. You are [height]cm tall and [age] years old!"
let firstName = "John"
let lastName = "Appleseed"
let age = 33
let height = 1.74
let tokenTable: [String: Printable] = [
"[firstName]": firstName,
"[lastName]": lastName,
"[age]": age,
"[height]": height]
for (token, value) in tokenTable
{
string = string.stringByReplacingOccurrencesOfString(token, withString: value.description)
}
println(string)
// Prints: "Hello there, John Appleseed. You are 1.74cm tall and 33 years old!"
You can store entities of any type as the values of tokenTable, as long as they conform to the Printable protocol.
To automate things further, you could define the tokenTable constant in a separate Swift file, and auto-generate that file by using a separate script to extract the tokens from your string-containing file.
Note that this approach will probably be quite inefficient with very large string files (but not much more inefficient than reading the whole string into memory on the first place). If that is a problem, consider processing the string file in a buffered way.
There is no built in mechanism for doing this, you will have to create your own.
Here is an example of a VERY rudimentary version:
var values = [
"name": "George"
]
var textFromFile = "Hello there, <name>!"
var parts = split(textFromFile, {$0 == "<" || $0 == ">"}, maxSplit: 10, allowEmptySlices: true)
var output = ""
for index in 0 ..< parts.count {
if index % 2 == 0 {
// If it is even, it is not a variable
output += parts[index]
}
else {
// If it is odd, it is a variable so look it up
if let value = values[parts[index]] {
output += value
}
else {
output += "NOT_FOUND"
}
}
}
println(output) // "Hello there, George!"
Depending on your use case, you will probably have to make this much more robust.