Swift 3.0 String concatenation leaves "Optional" [duplicate] - string

This question already has an answer here:
Swift 3 incorrect string interpolation with implicitly unwrapped Optionals
(1 answer)
Closed 6 years ago.
Since Swift 3.0 I have some troubles with Strings, especially with concatenation. 1st example would be what I used since I started using Swift to define my url strings.
internal let host: String! = "https://host.io/"
let urlString = "\(host)oauth/access_token"
where host is defined as at the beginning of the class. This worked perfectly until Swift 3.0, now that prints out like this:
Optional("https://host.io/")oauth/access_token
which is very strange. Now I have to write this
let urlString = host + "oauth/access_token"
To get the expected output.
https://host.io/oauth/access_token
Another - I guess similar problem I'm having with Strings is this. I'm again concatenating strings but this time I'm using + ilke with urlString - but this time that doesn't work. Line of code looks like this:
self.labelName.text = currentUser.name + " " + String(describing: ageComponents.year)
which unfortunately produces string like this: "My Name Optional(26)". In this case I don't have a solution String(describing: ageComponents.year) is not an optional and it doesn't allow me to do things like String(describing: ageComponents.year) ?? "whatever"
Anyone seen something similar?

In Swift 3 all properties of the native struct DateComponents are optionals unlike the Foundation NSDateComponents counterparts.
var year: Int? { get set }
You need to unwrap it. If you specified the unit year in ageComponents you can do that safely.

Related

Cant iterate over vec<&str> and pass element into option_env!()? [duplicate]

This question already has answers here:
println! error: expected a literal / format argument must be a string literal
(4 answers)
What does the word "literal" mean?
(11 answers)
Closed last month.
Sorry if this is a noob question.
I've created a .cargo/config.toml file in my project and configured some env variables like so:
[env]
GAME_ZERO_LEVEL = "0"
GAME_ZERO_MULTIPLIER = "0.1"
GAME_ONE_LEVEL = "1"
GAME_ONE_MULTIPLIER = "1.0"
GAME_TWO_LEVEL = "2"
GAME_TWO_MULTIPLIER = "2.5"
GAME_THREE_LEVEL = "3"
GAME_THREE_MULTIPLIER = "5.0"
GAME_FOUR_LEVEL = "4"
GAME_FOUR_MULTIPLIER = "10.0"
I will parse these into u32 and f32.
Anyway, I'm able to fetch these individually with
let value = option_env!("GAME_ZERO_LEVEL").unwrap();
Here is the problem, I want to fetch all env variables in a loop like so:
let env_keys: Vec<&str> = vec![
"GAME_ZERO_LEVEL",
"GAME_ZERO_MULTIPLIER",
"GAME_ONE_LEVEL",
"GAME_ONE_MULTIPLIER",
"GAME_TWO_LEVEL",
"GAME_TWO_MULTIPLIER",
"GAME_THREE_LEVEL",
"GAME_THREE_MULTIPLIER",
"GAME_FOUR_LEVEL",
"GAME_FOUR_MULTIPLIER",
];
env_keys.iter().for_each(|key| {
let value = option_env!(key).unwrap(); //error here
// do some stuff with it
}
But I get the following compile error
rustc: argument must be a string literal
Safe to say, Im pretty confused as my previous understanding was that &str are string literals, and that passing in a &str in a variable doesnt't work. Any help understanding this would be much appreciated!
Note: I cant use std::env::{var, vars}
Slight misconception there &str or more specifically &'static stris the type of string literals but string literals are just the ones you type literally like this: "this is a string literal", or this r"I'm a raw string literal" or even like this r#"I'm a raw string literal which can contain " wherever"#. Everything else is not a literal. Things that are not string literals also can have that type though.
Compare also string literals in Rust by example and the reference
option_env!() evaluates it's contents at compile time so you can't use it with runtime variables like your key.

How to get last 4 characters of a string? [duplicate]

This question already has answers here:
How do you use String.substringWithRange? (or, how do Ranges work in Swift?)
(33 answers)
Closed 7 years ago.
I need to seperate the last 4 letters of a string. How can I seperate it? The length of string is changing.
Example:
var a = "StackOverFlow"
var last4 = a.lastFour // That's what I want to do
print(last4) // prints Flow
Swift 2:
A solution is substringFromIndex
let a = "StackOverFlow"
let last4 = a.substringFromIndex(a.endIndex.advancedBy(-4))
or suffix on characters
let last4 = String(a.characters.suffix(4))
Swift 3:
In Swift 3 the syntax for the first solution has been changed to
let last4 = a.substring(from:a.index(a.endIndex, offsetBy: -4))
Swift 4+:
In Swift 4 it becomes more convenient:
let last4 = a.suffix(4)
The type of the result is a new type Substring which behaves as a String in many cases. However if the substring is supposed to leave the scope where it's created in you have to create a new String instance.
let last4 = String(a.suffix(4))
String substr = a.substring(a.length() - 4)
syntax is wrong. no type before vars in Swift.
let a = "1234567890"
let last4 = String(a.characters.suffix(4))
print(last4)
works on Swift 3.0

Is there an equivalent to the string function String(format: ...) using Swift formatting

I'm starting to like the Swift string formatting since it uses variable names in the string rather than ambiguous formatting tags like "%#"
I want to load a large string from a file that has Swift-style formatting in it (like this)
Now is the time for all good \(who) to come to babble incoherently.
Then I want to feed the contents of that String variable into a statement that lest me replace
\(who)
with the contents of the constant/variable who at runtime.
The code below works with a string constant as the formatting string.
let who = "programmers"
let aString = "Now is the time for all good \(who) to come to babble incoherently."
That code does formatting of a quoted string that appears in-line in my code.
Instead I want something like the code
let formatString = "Now is the time for all good %# to come to babble incoherently."
aString = String(format: formatString, who)
But where I can pass in a Swift-style format string in a constant/variable I read from a file.
Is that possible? I didn't have any luck searching for it since I wasn't exactly sure what search terms to use.
I can always use C-style string formatting and the String class' initWithFormat method if I have to...
I don't think there's a way to do this. String interpolation is implemented via conforming to the StringInterpolationConvertible protocol, and presumably you're hoping to tap into that in the same way you can tap into the methods required by StringLiteralConvertible, a la:
let someString = toString(42)
// this is the method String implements to conform to StringLiteralConvertible
let anotherString = String(stringLiteral: someString)
// anotherString will be "42"
print(anotherString)
Unfortunately, you can't do quite the same trick with StringInterpolationConvertible. Seeing how the protocol works may help:
struct MyString: Printable {
let actualString: String
var description: String { return actualString }
}
extension MyString: StringInterpolationConvertible {
// first, this will get called for each "segment"
init<T>(stringInterpolationSegment expr: T) {
println("Processing segment: " + toString(expr))
actualString = toString(expr)
}
// here is a type-specific override for Int, that coverts
// small numbers into words:
init(stringInterpolationSegment expr: Int) {
if (0..<4).contains(expr) {
println("Embigening \(expr)")
let numbers = ["zeo","one","two","three"]
actualString = numbers[expr]
}
else {
println("Processing segment: " + toString(expr))
actualString = toString(expr)
}
}
// finally, this gets called with an array of all of the
// converted segments
init(stringInterpolation strings: MyString...) {
// strings will be a bunch of MyString objects
actualString = "".join(strings.map { $0.actualString })
}
}
let number = 3
let aString: MyString = "Then shalt thou count to \(number), no more, no less."
println(aString)
// prints "Then shalt thou count to three, no more, no less."
So, while you can call String.init(stringInterpolation:) and String.init(stringInterpolationSegment:) directly yourself if you want (just try String(stringInterpolationSegment: 3.141) and String(stringInterpolation: "blah", "blah")), this doesn't really help you much. What you really need is a facade function that coordinates the calls to them. And unless there's a handy pre-existing function in the standard library that does exactly that which I've missed, I think you're out of luck. I suspect it's built into the compiler.
You could maybe write your own to achieve your goal, but a lot of effort since you'd have to break up the string you want to interpolate manually into bits and handle it yourself, calling the segment init in a loop. Also you'll hit problems with calling the combining function, since you can't splat an array into a variadic function call.
I don't think so. The compiler needs to be able to resolve the interpolated variable at compile time.
I'm not a Swift programmer, specifically, but I think you can workaround it to something pretty close to what you want using a Dictionary and standard string-replacing and splitting methods:
var replacement = [String: String]()
replacement["who"] = "programmers"
Having that, you can try to find the occurrences of "\(", reading what is next and prior to a ")", (this post can help with the split part, this one, with the replacing part), finding it in the dictionary, and reconstructing your string from the pieces you get.
this one works like a charm:
let who = "programmers"
let formatString = "Now is the time for all good %# to come to babble incoherently."
let aString = String(format: formatString, who)

Convert string to table in lua [duplicate]

This question already has answers here:
String to Table in Lua
(2 answers)
Closed 9 years ago.
I am newbie in lua. I need to convert following string to lua table. How could I do this?
str = "{a=1, b=2, c={d=3,e=4} }"
I want to convert this string to lua table, so that I can access it like this:
print(str['a']) -- Output : 1
print(str['c']['d']) -- Output : 3
You could simply add a str = to the beginning of the string and let the interpreter load that string as a chunk for you. Note that loadstring doesn't run the chunk but returns a function. So you add () to call that function right away and actually execute the code:
loadstring("str = "..str)()
This would do the same thing:
str = loadstring("return "..str)()
If you don't generate the string yourself, that can be dangerous though (because any code would be executed). In that case, you might want to parse the string manually, to make sure that it's actually a table and contains no bad function calls.

repeat string with LINQ/extensions methods [duplicate]

This question already has answers here:
Is there an easy way to return a string repeated X number of times?
(21 answers)
Closed 9 years ago.
Just a curiosity I was investigating.
The matter: simply repeating (multiplying, someone would say) a string/character n times.
I know there is Enumerable.Repeat for this aim, but I was trying to do this without it.
LINQ in this case seems pretty useless, because in a query like
from X in "s" select X
the string "s" is being explored and so X is a char. The same is with extension methods, because for example "s".Aggregate(blablabla) would again work on just the character 's', not the string itself. For repeating the string something "external" would be needed, so I thought lambdas and delegates, but it can't be done without declaring a variable to assign the delegate/lambda expression to.
So something like defining a function and calling it inline:
( (a)=>{return " "+a;} )("a");
or
delegate(string a){return " "+a}(" ");
would give a "without name" error (and so no recursion, AFAIK, even by passing a possible lambda/delegate as a parameter), and in the end couldn't even be created by C# because of its limitations.
It could be that I'm watching this thing from the wrong perspective. Any ideas?
This is just an experiment, I don't care about performances, about memory use... Just that it is one line and sort of autonomous. Maybe one could do something with Copy/CopyTo, or casting it to some other collection, I don't know. Reflection is accepted too.
To repeat a character n-times you would not use Enumerable.Repeat but just this string constructor:
string str = new string('X', 10);
To repeat a string i don't know anything better than using string.Join and Enumerable.Repeat
string foo = "Foo";
string str = string.Join("", Enumerable.Repeat(foo, 10));
edit: you could use string.Concat instead if you need no separator:
string str = string.Concat( Enumerable.Repeat(foo, 10) );
If you're trying to repeat a string, rather than a character, a simple way would be to use the StringBuilder.Insert method, which takes an insertion index and a count for the number of repetitions to use:
var sb = new StringBuilder();
sb.Insert(0, "hi!", 5);
Console.WriteLine(sb.ToString());
Otherwise, to repeat a single character, use the string constructor as I've mentioned in the comments for the similar question here. For example:
string result = new String('-', 5); // -----
For the sake of completeness, it's worth noting that StringBuilder provides an overloaded Append method that can repeat a character, but has no such overload for strings (which is where the Insert method comes in). I would prefer the string constructor to the StringBuilder if that's all I was interested in doing. However, if I was already working with a StringBuilder, it might make sense to use the Append method to benefit from some chaining. Here's a contrived example to demonstrate:
var sb = new StringBuilder("This item is ");
sb.Insert(sb.Length, "very ", 2) // insert at the end to append
.Append('*', 3)
.Append("special")
.Append('*', 3);
Console.WriteLine(sb.ToString()); // This item is very very ***special***

Resources