Swift NSAlert() argument print string with spaces - swift

How do a print the array below to display the full string?
alert.informativeText = CommandLine.arguments[4]
This prints fine if it's one word. Argument Test
Test
However if the argument is This Is A Test. It still prints just the first word:
Test
Full Code:
CommandLine.arguments[1]{
func dialogOKCancel(title: String) -> Bool
{
let alert = NSAlert()
alert.informativeText = CommandLine.arguments[4]
alert.alertStyle = NSAlert.Style.warning
alert.addButton(withTitle: "Dismiss")
return alert.runModal() == NSApplication.ModalResponse.alertFirstButtonReturn
}
_ = dialogOKCancel(title: "")

The space character is the argument separator in the command line.
You have to quote the string
/path/to/executable 'This is A Test'
or to escape
/path/to/executable This\ is\ A\ Test
the spaces in the string when calling the executable.

Command line arguments are always split with spaces. Although "This Is A Test" might look like a single argument, it is four arguments - "This", "Is", "A" and "Test".
What you are trying to do seems to be printing all the arguments. In that case, you should drop the first element of CommandLine.arguments (that's the command itself) and then join the strings:
alert.informativeText = CommandLine.arguments.dropFirst().joined(separator: " ")

Related

Access an optional capture by name when using Swift Regex Builder

I'm just getting started with regular expressions and Swift Regex, so a heads up that my terminology my be incorrect. I have boiled this problem down to a very simple task:
I have input lines that have either just one word (a name) or start with the word "Test" followed by one space and then a name. I want to extract the name and also be able to access - without using match indices - the match to "Test " (which may be nil). Here is code that better describes the problem:
import RegexBuilder
let line1 = "Test John"
let line2 = "Robert"
let nameReference = Reference(String.self)
let testReference = Reference(String.self)
let regex = Regex {
Optionally {
Capture(as:testReference) {
"Test "
} transform : { text in
String(text)
}
}
Capture(as:nameReference) {
OneOrMore(.any)
} transform : { text in
String(text)
}
}
if let matches = try? regex.wholeMatch(in: line1) { // USE line1 OR line2 HERE
let theName = matches[nameReference]
print("Name is \(theName)")
// using index to access the test flag works fine for both line1 and line2:
if let flag = matches.1, flag == "Test " {
print("Using index: This is a test line")
} else {
print("Using index: Not a test line")
}
// but for line2, attempting to access with testReference crashes:
if matches[testReference] == "Test " { // crashes for line2 (not surprisingly)
print("Using reference: This is a test line")
} else {
print("Using reference: Not a test line")
}
}
When regex.wholeMatch() is called with line1 things work as expected with output:
Name is John
Using index: This is a test line
Using reference: This is a test line
but when called with line2 it crashes with a SIGABRT and output:
Name is Robert
Using index: Not a test line
Could not cast value of type 'Swift.Optional<Swift.Substring>' (0x7ff84bf06f20) to 'Swift.String' (0x7ff84ba6e918).
The crash is not surprising, because the Capture(as:testReference) was never matched.
My question is: is there a way to do this without using match indices (matches.1)? An answer using Regex Builder would be much appreciated:-)
The documentation says Regex.Match has a subscript(String) method which "returns nil if there's no capture with that name". That would be ideal, but it works only when the match output is type AnyRegexOutput.
I don't think you can get away with not using indexes, or at least code that knows the index but might hide it. Regular expression parsing works like that in any language, because it's always assumed that you know the order of elements in the expression.
For something like this, your example could be simplified to something like
let nameRegex = Regex {
ZeroOrMore("Test ")
Capture { OneOrMore(.anyNonNewline) }
}
if let matches = try? nameRegex.wholeMatch(in: line2) {
let (_, name) = matches.output
print("Name: \(name)")
}
That works for both of your sample lines. The let (_, name) doesn't use a numeric index but it's effectively the same thing since it uses index 1 as the value for name.
If your data is as straightforward as these examples, a regular expression may be overkill. You could work with if line1.hasPrefix("Test ") to detect lines with Test and then drop the first 5 characters, for example.

Swift string comparison failure due to newlines

I am trying to compare two strings
1. String read from a .strings file using the api, String(contentsOf: localizableFilePath, encoding: .ascii).propertyListFromStringsFileFormat()
2. Strings to be written to the strings file
The string comparison fails when there are newlines in the strings, i,e
the string 1 has newLine character in them so its like
"something
something"
and string 2 is like "something \nsomething"
and the comparison fails because of this.
You can try replacing occurrences of newline characters with an empty string: For example:
let inputString = "Something \nSomething"
let test = "Something Something"
test == inputString.replacingOccurrences(of: "\n", with: "") // true

Print in Swift 3

i would like to know what's the different between these two way to print the object in Swift.
The result seems identical.
var myName : String = "yohoo"
print ("My name is \(myName).")
print ("My name is ", myName, ".")
There is almost no functional difference, the comma simply inputs a space either before or after the string.
let name = "John"
// both print "Hello John"
print("Hello", name)
print("Hello \(name)")
You can use the \(variable) syntax to create interpolated strings, which are then printed just as you input them. However, the print(var1,var2) syntax has some "facilities":
It automatically adds a space in between each two variables, and that is called separator
You can customise your separator based on the context, for example:
var hello = "Hello"
var world = "World!"
print(hello,world,separator: "|") // prints "Hello|World!"
print(hello,world,separator: "\\//") // prints "Hello\\//World!"
No difference between the two
var favoriteFood: String = "Pizza" //favoriteFood = Pizza
//both print the same thing
print("My favorite food is", favoriteFood)
print("My favorite food is \(favoriteFood)")

fatal error: Can't form a Character from an empty String

So I have function that strips off a trailing ", " (comma + space) at the end of a string and I'm getting the above error even though I'm ensuring that the string is not empty. The following code:
print("stripping trailing commas")
for var detail in details {
if detail.contains(",") {
print(detail)
detail.remove(at: detail.endIndex) // <-- Removes last space
detail.remove(at: detail.endIndex) // <-- Removes last comma
}
}
...results int the following console output:
stripping trailing commas
2016,
fatal error: Can't form a Character from an empty String
The first instance detail.remove(at: detail.endIndex) is being highlighted by the debugger, and while I can't be sure the space is present from the console message, I'm adding ", " at the end of each entry in a list so any string that actually contains a comma should not only have characters (as the console indicates) but it should have an extra two chars at the end that need to be stripped.
Thanks in advance, for any help on what's causing the error and how to resolve?
Try change
detail.remove(at: detail.endIndex)
to
detail.remove(at: detail.index(before: detail.endIndex))
A simple way to do this without using import Foundation (needed for contains()) or calculating indexes would be something like this:
let details = ["one, two, three, ", "a, b", "once, twice, thrice, so nice, ", ""]
let filtered = details.map { (original: String) -> String in
guard original.hasSuffix(", ") else { return original }
return String(original.characters.dropLast(2))
}
print(filtered) // -> "["one, two, three", "a, b", "once, twice, thrice, so nice", ""]\n"
This won't remove any empty strings that are in the returned array. If you need that functionality it can easily be added.

Print String using variadic params without comma, newline and brackets in Swift

While I was trying to use Swift's String(format: format, args) method, I found out that I cannot print the formatted string directly without newline(\n) and brackets being added.
So for example, I have a code like this:
func someFunc(string: String...) {
print(String(format: "test %#", string))
}
let string = "string1"
someFunc(string, "string2")
the result would be:
"test (\n string1,\n string2\n)\n"
However, I intend to deliver the result like this:
"test string1 string2"
How can I make the brackets and \n not being printed?
Since string parameter is a sequence, you can use joinWithSeparator on it, like this:
func someFunc(string: String...) {
print(string.joinWithSeparator(" "))
}
someFunc("quick", "brown", "fox", "jumps", "over", "the", "lazy", "dog")
You will first need to concatenate your list of input strings, otherwise it will print as a list, hence the commas and parentheses. You can additionally strip out the newline characters and whitespace from the ends of the string using a character set.
var stringConcat : String = ''
for stringEntry in string {
stringConcat += stringEntry.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet())
}
Then just print out the stringConcat.