Create string template in Swift? - string

I would like to store a string as a constant in Swift so I can reuse it and inject variables into it. For example, I can do this in C#:
var template = "Your name is {0} and your age is {1}."
someLabel.text = string.Format(template, "John", 35)
some2Label.text = string.Format(template, "Jane", 33)
How can I accomplish this in Swift so I can reuse the string template?

Use swift's printf-style syntax to save the template and then use it like this:
var template = "Your name is %# and your age is %d."
someLabel.text = String(format: template, "John", 35)
some2Label.text = String(format: template, "Jane", 33)
If you haven't used this style of syntax before here is a rough guide:
%# : String (or, as nhgrif pointed out, the description / descriptionWithLocale property of an NSObject)
%d : Int
%f : Double
%.2f : Double with precision of 2, e.g. 2.2342 -> 2.23
Here's the documentation if you require more precision.

You already have an answer, but if you want type safety and to localize your code, you can use enums like this:
enum Greeting: CustomStringConvertible {
case SayHello(String)
var description:String {
switch (self) {
case .SayHello(let name):
return "Say hello to \(name)?"
}
}
}
let a = Greeting.SayHello("my little friend")
Note that doesn't preclude you from taking a hybrid approach of putting all your string templates in one location and building them in a type safe enum via the String(format:...) approach. You would just need to implement it carefully (but only once).

You can use a template engine such as https://github.com/groue/GRMustache.swift.

Related

SwiftUI: Use of different colours within same Text view

I have a section of text where I am using .replacingOccurrences to display the users' answer within the question sentence:
Text((question.text)
.replacingOccurrences(of: "_____", with:
question.answers[question.userAnswer]
))
.font(Font.custom("ClearSans-Bold", size: 18))
.foregroundColor(.black )
.padding(.bottom, 20)
.multilineTextAlignment(.center)
I want the users' answer question.answers[question.userAnswer] to be a different colour (red/green) to the main body of the text (similar to attached image) however I'm new to SwiftUI so not sure how to add this in.
Image 1
Here's an extension for String that does pretty much what you want:
extension String {
func replacingOccurrences(of: String, with: [Text]) -> Text {
return self.components(separatedBy: of).enumerated().map({(i, s) in
return i < with.count ? Text(s) + with[i] : Text(s)
}).reduce(Text(""), { (r, t) in
return r + t
})
}
}
It uses concatenation of Text elements as George_E suggested. You can use it like this:
struct ContentView: View {
let question: String = "The witch found the concoction extremely _____. _____ makes better ones."
let answers: [String] = ["nauseate", "A friend of her's"]
var body: some View {
question.replacingOccurrences(of: "_____", with: self.answers.map({s in Text(s).foregroundColor(.red)})).foregroundColor(.secondary)
}
}
Result:
You may want to add some extra code for handling cases where the number of answers does not match the occurrences of _____.

how to concatenate a string to a numeric,for eg:i need tkr1,tkr2... based on a for loop

string str1=tkr;
for(i=1;i<=10;i++)
{
string str2=str1+i;
sopln(str2);
}
I need result like this..
tkr1
tkr2
tkr3
tkr4
tkr5...could any one re-write the code which could give the proper output?
Its not mentioned which language you are using so it would be not possible to give exact answer:
This should work in most of the languages :
String str1=tkr;
String str2 = "";
for(i=1;i<=10;i++)
{
str2=str2 + str1+i + " ";
}
print(str2)
And use mutable strings if you are using java

String interpolation in Swift

A function in swift takes any numeric type in Swift (Int, Double, Float, UInt, etc).
the function converts the number to a string
the function signature is as follows :
func swiftNumbers <T : NumericType> (number : T) -> String {
//body
}
NumericType is a custom protocol that has been added to numeric types in Swift.
inside the body of the function, the number should be converted to a string:
I use the following
var stringFromNumber = "\(number)"
which is not so elegant, PLUS : if the absolute value of the number is strictly inferior to 0.0001 it gives this:
"\(0.000099)" //"9.9e-05"
or if the number is a big number :
"\(999999999999999999.9999)" //"1e+18"
is there a way to work around this string interpolation limitation? (without using Objective-C)
P.S :
NumberFormater doesn't work either
import Foundation
let number : NSNumber = 9_999_999_999_999_997
let formatter = NumberFormatter()
formatter.minimumFractionDigits = 20
formatter.minimumIntegerDigits = 20
formatter.minimumSignificantDigits = 40
formatter.string(from: number) // "9999999999999996.000000000000000000000000"
let stringFromNumber = String(format: "%20.20f", number) // "0.00000000000000000000"
Swift String Interpolation
1) Adding different types to a string
2) Means the string is created from a mix of constants, variables, literals or expressions.
Example:
let length:Float = 3.14
var breadth = 10
var myString = "Area of a rectangle is length*breadth"
myString = "\(myString) i.e. = \(length)*\(breadth)"
Output:
3.14
10
Area of a rectangle is length*breadth
Area of a rectangle is length*breadth i.e. = 3.14*10
Use the Swift String initializer: String(format: <#String#>, arguments: <#[CVarArgType]#>)
For example:
let stringFromNumber = String(format: "%.2f", number)
String and Characters conforms to StringInterpolationProtocol protocol which provide more power to the strings.
StringInterpolationProtocol - "Represents the contents of a string literal with interpolations while it’s being built up."
String interpolation has been around since the earliest days of Swift, but in Swift 5.0 it’s getting a massive overhaul to make it faster and more powerful.
let name = "Ashwinee Dhakde"
print("Hello, I'm \(name)")
Using the new string interpolation system in Swift 5.0 we can extend String.StringInterpolation to add our own custom interpolations, like this:
extension String.StringInterpolation {
mutating func appendInterpolation(_ value: Date) {
let formatter = DateFormatter()
formatter.dateStyle = .full
let dateString = formatter.string(from: value)
appendLiteral(dateString)
}
}
Usage: print("Today's date is \(Date()).")
We can even provide user-defined names to use String-Interpolation, let's understand with an example.
extension String.StringInterpolation {
mutating func appendInterpolation(JSON JSONData: Data) {
guard
let JSONObject = try? JSONSerialization.jsonObject(with: JSONData, options: []),
let jsonData = try? JSONSerialization.data(withJSONObject: JSONObject, options: .prettyPrinted) else {
appendInterpolation("Invalid JSON data")
return
}
appendInterpolation("\n\(String(decoding: jsonData, as: UTF8.self))")
}
}
print("The JSON is \(JSON: jsonData)")
Whenever we want to provide "JSON" in the string interpolation statement, it will print the .prettyPrinted
Isn't it cool!!

Just Difference in C#

What is the differ between string.Join & string.Concat
similarly what is the diff between string.Equals & string.Compare
Show me with some example for each. I already searched but didn't understand.
Thanks in Advance.
Join combines several strings with a separator in between; this is most often used if you have a list and want to format it in a way that there is a separator (e.g. a comma) between each element. Concat just appends them all after another. In a way, Join with an empty separator is equivalent to Concat.
Equals determines whether two strings are considered equal, Compare is for determining a sort order between two strings.
Honestly, though, this is all explained very well in the documentation.
With .NET 4.0, String.Join() uses StringBuilder class internally so it is more efficient.
Whereas String.Concat() uses basic concatenation of String using "+" which is of course not an efficient approach as String is immutable.
I compared String.Join() in .NET 2.0 framework where its implementation was different(it wasn't using StringBuilder in .NET 2.0). But with .NET 4.0, String.Join() is using StringBuilder() internally so its like easy wrapper on top of StringBuilder() for string concatenation.
Microsoft even recommends using StringBuilder class for any string concatenation.
Program that joins strings [C#]
using System;
class Program
{
static void Main()
{
string[] arr = { "one", "two", "three" };
// "string" can be lowercase, or...
Console.WriteLine(string.Join(",", arr));
// ... "String" can be uppercase:
Console.WriteLine(String.Join(",", arr));
}
}
Output -
one,two,three
one,two,three
Concat:
using System;
class Program
{
static void Main()
{
// 1.
// New string called s1.
string s1 = "string2";
// 2.
// Add another string to the start.
string s2 = "string1" + s1;
// 3.
// Write to console.
Console.WriteLine(s2);
}
}
Output -
string1string2
these two methods are quite related. Although it hasn't been done, equals could have been implemented using compareTo:
public boolean equals(Object o)
{
if (this == anObject)
{
return true;
}
if (o instanceof String)
{
String s = (String)o;
return compareTo(s) == 0;
}
return false;
}
Also, s1.equals(s2) == true implies s1.compareTo(s2) == 0 (and vice versa), and s1.equals(s2) == false implies s1.compareTo(s2) != 0 (and vice versa).
However, and this is important, this does not have to be the case for all classes. It is for String, but no rule prohibits different natural orders for other classes.

Is there a .NET function to remove the first (and only the first) occurrence at the start of a string?

I was using the TrimStart function to do the following:
var example = "Savings:Save 20% on this stuff";
example = example.TrimStart("Savings:".ToCharArray());
I was expecting this to result in example having a value of "Save 20% on this stuff".
However, what I got was "e 20% on this stuff".
After reading the documentation on TrimStart I understand why, but now I'm left wondering if there is a function in .NET that does what I was trying to do in the first place?
Does anyone know of a function so I don't have to create my own and keep track of it?
I don't think such a method exists but you can easily do it using StartsWith and Substring:
s = s.StartsWith(toRemove) ? s.Substring(toRemove.Length) : s;
You can even add it as an extension method:
public static class StringExtension
{
public static string RemoveFromStart(this string s, string toRemove)
{
if (s == null)
{
throw new ArgumentNullException("s");
}
if (toRemove == null)
{
throw new ArgumentNullException("toRemove");
}
if (!s.StartsWith(toRemove))
{
return s;
}
return s.Substring(toRemove.Length);
}
}
No, I don't believe there's anything which does this built into the framework. It's a somewhat unusual requirement, IMO.
Note that you should think carefully about whether you're trying to remove "the first occurrence" or remove the occurrence at the start of the string, if there is one. For example, think what you'd want to do with: "Hello. Savings: Save 20% on this stuff".
You can do that quite easily using a regular expression.
Remove the occurrence on the beginning of the string:
example = Regex.Replace(example, #"^Savings:", "");
Remove the first occurrence in the string:
example = Regex.Replace(example, #"(?<!Savings:.*)Savings:", "");

Resources