Swift distance() method throws fatal error: can not increment endIndex - xcode

I was trying to find a substring match in a string, and get the matched position.
I can't figure out what's wrong with the following code:
let str1 = "hello#゚Д゚"
let cmp = "゚Д゚"
let searchRange = Range(start: str1.startIndex, end: str1.endIndex)
let range = str1.rangeOfString(cmp, options: .allZeros, range: searchRange)
println("\(searchRange), \(range!)") // output: 0..<9, 6..<9
let dis = distance(searchRange.startIndex, range!.startIndex) // fatal error: can not increment endIndex! reason: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0).
// let dis = distance(searchRange.startIndex, range!.endIndex) // This will go and output: distance=7
println("distance=\(dis)")
As the comments suggested, although the range had valid values, the distance() method threw a fatal error.
If I'm wrong about the use of distance(), what method should I use to archive the target?
Any advice would be helpful. Thanks.

range!.startIndex points here:
"hello#゚Д゚"
^
But, in this case, #゚ is a single character in Swift.
Therefore, This code:
for var idx = searchRange.startIndex; idx != range!.startIndex; idx = idx.successor() {
println("\(idx): \(str1[idx])");
}
prints:
0: h
1: e
2: l
3: l
4: o
5: #゚
7: Д゚
fatal error: Can't form a Character from an empty String
// and emits BAD_INSTRUCTION exception
As you can see range!.startIndex never matches to the character boundaries, and the for loop run out the string. That's why you see the exception.
In theory, since String is considered as "Collection of Characters" in Swift, "゚Д゚" should not be a substring of "hello#゚Д゚".
I think .rangeOfString() uses NSString implementation which treats string as a sequence of unichar. I don't know this should be considered as a bug or not.

Try this:
func search<C: CollectionType where C.Generator.Element: Equatable>(col1: C, col2: C) -> C.Index? {
if col2.startIndex == col2.endIndex {
return col1.startIndex
}
var col1Ind = col1.startIndex
while col1Ind != col1.endIndex {
var ind1 = col1Ind
var ind2 = col2.startIndex
while col1[ind1] == col2[ind2] {
++ind1; ++ind2
if ind2 == col2.endIndex { return col1Ind }
if ind1 == col1.endIndex { return nil }
}
++col1Ind
}
return nil
}
Searches for the first instance of the col2 sequence in col1. If found, returns the index of the start of the sub-sequence. If not found, returns nil. If col2 is empty, returns the startIndex of col1.

Related

Swift 1.2, capture character from a word

My problem is how to get character from a word
The result I needed is
DisplayChar("asd",1)
and it will display "a"
func DisplayChar(word : String, number : Int) -> String{
let i: Int = count(word)
var result = 0
result = i - (i - number)
var str = ""
var j = 0
for j = 0; j < result; j++ {
str = str + word[j]
}
return str
}
DisplayChar("xyz", 2)
This code should work
let sentence = "Hello world"
let characters = Array(sentence)
print(characters[0]) // "H"
There are a couple good solutions in this answer that may work, two good ones duplicated below.
Convert to Array
let word = "test"
var firstChar = Array(word)[0] // t
(Note: this assumes a UTF8 or ASCII encoded string, but that is likely fine for school.)
Create Your Own Extension
First an extension of String to handle subscripts:
extension String {
subscript (i: Int) -> Character {
return self[self.startIndex.advancedBy(i)]
}
subscript (i: Int) -> String {
return String(self[i] as Character)
}
subscript (r: Range<Int>) -> String {
let start = startIndex.advancedBy(r.startIndex)
let end = start.advancedBy(r.endIndex - r.startIndex)
return self[Range(start ..< end)]
}
}
Then you can just use:
let word = "test"
var firstChar = word[0] // t
Swift strings have a method called substringToIndex, "asd".substringToIndex(1) will return "a".
I'm not sure if it works on Swift 1.2, though.

xcode: need to convert strings to double and back to string

this is my line of code.
budgetLabel.text = String((budgetLabel.text)!.toInt()! - (budgetItemTextBox.text)!.toInt()!)
the code works, but when I try to input a floating value into the textbox the program crashes. I am assuming the strings need to be converted to a float/double data type. I keep getting errors when i try to do that.
In Swift 2 there are new failable initializers that allow you to do this in more safe way, the Double("") returns an optional in cases like passing in "abc" string the failable initializer will return nil, so then you can use optional-binding to handle it like in the following way:
let s1 = "4.55"
let s2 = "3.15"
if let n1 = Double(s1), let n2 = Double(s2) {
let newString = String( n1 - n2)
print(newString)
}
else {
print("Some string is not a double value")
}
If you're using a version of Swift < 2, then old way was:
var n1 = ("9.99" as NSString).doubleValue // invalid returns 0, not an optional. (not recommended)
// invalid returns an optional value (recommended)
var pi = NSNumberFormatter().numberFromString("3.14")?.doubleValue
Fixed: Added Proper Handling for Optionals
let budgetLabel:UILabel = UILabel()
let budgetItemTextBox:UITextField = UITextField()
budgetLabel.text = ({
var value = ""
if let budgetString = budgetLabel.text, let budgetItemString = budgetItemTextBox.text
{
if let budgetValue = Float(budgetString), let budgetItemValue = Float(budgetItemString)
{
value = String(budgetValue - budgetItemValue)
}
}
return value
})()
You need to be using if let. In swift 2.0 it would look something like this:
if let
budgetString:String = budgetLabel.text,
budgetItemString:String = budgetItemTextBox.text,
budget:Double = Double(budgetString),
budgetItem:Double = Double(budgetItemString) {
budgetLabel.text = String(budget - budgetItem)
} else {
// If a number was not found, what should it do here?
}

How to check for a Not a Number (NaN) in Swift 2

The following method calculates the percentage using two variables.
func casePercentage() {
let percentage = Int(Double(cases) / Double(calls) * 100)
percentageLabel.stringValue = String(percentage) + "%"
}
The above method is functioning well except when cases = 1 and calls = 0.
This gives a fatal error: floating point value can not be converted to Int because it is either infinite or NaN
So I created this workaround:
func casePercentage() {
if calls != 0 {
let percentage = Int(Double(cases) / Double(calls) * 100)
percentageLabel.stringValue = String(percentage) + "%"
} else {
percentageLabel.stringValue = "0%"
}
}
This will give no errors but in other languages you can check a variable with an .isNaN() method. How does this work within Swift2?
You can "force unwrap" the optional type using the ! operator:
calls! //asserts that calls is NOT nil and gives a non-optional type
However, this will result in a runtime error if it is nil.
One option to prevent using nil or 0 is to do what you have done and check if it's 0.
The second is option is to nil-check
if calls != nil
The third (and most Swift-y) option is to use the if let structure:
if let nonNilCalls = calls {
//...
}
The inside of the if block won't run if calls is nil.
Note that nil-checking and if let will NOT protect you from dividing by 0. You will have to check for that separately.
Combining second and your method:
//calls can neither be nil nor <= 0
if calls != nil && calls > 0

Swift. Want an if statement that will give an error if value is not an integer

I am new to this an am trying to learn as much as I can. I have a variable that has a numerical value, I want an if statement that will look at this value and give an err if this value is not an integer. Can someone help?
Thanks
You can check it like this and then work with number inside the if clause:
if let number = numericalValue as? Int {
// numericalValue is an Int
} else {
// numericalValue is not an Int
}
I use Int() coupled with an if statement to achieve this:
//var number = 17 - will print "17 is an integer"
//var number = "abc" - will print "Error"
if let numberTest = Int(number) {
print("\(number) is an integer")
} else {
print("Error")
}
I managed to solve it in the end. I found the remainder operator in the Swift manual. Thought if I used that, divided by 1, if there was a remainder then the original value couldn't be an integer. So my code was - else if ((Double(guessEnteredNumber.text!)!) % 1 ) > 0 { resultText.text = "You need to guess a whole number between 1 and 5"
In swift 2 you can now use the 'guard' keyword like this
guard let number = myNumber as Int else {
// myNumber is not an Int
return
}
// myNumber is an Int and you can use number as it is not null
You can replace the 'let' keyword by a 'var' if you need to modify 'number' afterward

Strange error when sorting strings with D

I am in the process of learning D (I decided it would be a better beginner friendly language than C++) and I decided to give myself the excercise of implementing a general quicksort in D. My program runs fine when sorting integers but it doesn't compile and throws a strange error when sorting strings.
Here is my code:
import std.stdio, std.algorithm;
T[] quickSort(T)(T[] input) {
if (input.length <= 1) {return input;}
ulong i = input.length/2;
auto pivot = input[i];
input = input.remove(i);
T[] lesser = [];
T[] greater = [];
foreach (x; input) {
if (x<=pivot)
{
lesser ~= x;
}
else
{
greater ~=x;
}
}
return (quickSort(lesser) ~ cast(T)pivot ~ quickSort(greater));
}
void main() {
//Sort integers, this works fine
//writeln(quickSort([1,4,3,2,5]));
//Sort string, throws weird error
writeln(quickSort("oidfaosnuidafpsbufiadsb"));
}
When I run it on a string it throws this error:
/usr/share/dmd/src/phobos/std/algorithm.d(7397): Error: template std.algorithm.move does not match any function template declaration. Candidates are:
/usr/share/dmd/src/phobos/std/algorithm.d(1537): std.algorithm.move(T)(ref T source, ref T target)
/usr/share/dmd/src/phobos/std/algorithm.d(1630): std.algorithm.move(T)(ref T source)
/usr/share/dmd/src/phobos/std/algorithm.d(1537): Error: template std.algorithm.move cannot deduce template function from argument types !()(dchar, dchar)
/usr/share/dmd/src/phobos/std/algorithm.d(7405): Error: template std.algorithm.moveAll does not match any function template declaration. Candidates are:
/usr/share/dmd/src/phobos/std/algorithm.d(1786): std.algorithm.moveAll(Range1, Range2)(Range1 src, Range2 tgt) if (isInputRange!(Range1) && isInputRange!(Range2) && is(typeof(move(src.front, tgt.front))))
/usr/share/dmd/src/phobos/std/algorithm.d(7405): Error: template std.algorithm.moveAll(Range1, Range2)(Range1 src, Range2 tgt) if (isInputRange!(Range1) && isInputRange!(Range2) && is(typeof(move(src.front, tgt.front)))) cannot deduce template function from argument types !()(string, string)
helloworld.d(9): Error: template instance std.algorithm.remove!(cast(SwapStrategy)2, string, ulong) error instantiating
helloworld.d(31): instantiated from here: quickSort!(immutable(char))
helloworld.d(31): Error: template instance helloworld.quickSort!(immutable(char)) error instantiating
the problem is that strings are immutable so remove won't work (as it manipulates the string)
you can fix that by not removing and not inserting the pivot in the concat:
auto pivot = input[i];
//input = input.remove(i); //<- remove this line
T[] lesser = [];
//...
return (quickSort(lesser) ~ quickSort(greater)); //<- remove cast(T)pivot ~
or by passing in a dup:
writeln(quickSort("oidfaosnuidafpsbufiadsb".dup));
You have to put a "d" behind the string to make it utf-32, otherwise remove won't accept it.
writeln(quickSort("oidfaosnuidafpsbufiadsb"d.dup));

Resources