Swift 2.0 substringwithrange - substring

I've Xcode 7 gm, with swift 2.0 what is equivalent espression of:
Let myNSString = "full text container"
myNSString.substringWithRange(NSRange(location: 0, length: 3))
With new string class?

Try this:
let myString = "full text container"
myString[myString.startIndex..<myString.startIndex.advancedBy(3)]

You can use these extensions:
Swift 2
extension String
{
func substringWithRange(start: Int, end: Int) -> String
{
if (start < 0 || start > self.characters.count)
{
print("start index \(start) out of bounds")
return ""
}
else if end < 0 || end > self.characters.count
{
print("end index \(end) out of bounds")
return ""
}
let range = Range(start: self.startIndex.advancedBy(start), end: self.startIndex.advancedBy(end))
return self.substringWithRange(range)
}
func substringWithRange(start: Int, location: Int) -> String
{
if (start < 0 || start > self.characters.count)
{
print("start index \(start) out of bounds")
return ""
}
else if location < 0 || start + location > self.characters.count
{
print("end index \(start + location) out of bounds")
return ""
}
let range = Range(start: self.startIndex.advancedBy(start), end: self.startIndex.advancedBy(start + location))
return self.substringWithRange(range)
}
}
Swift 3
extension String
{
func substring(start: Int, end: Int) -> String
{
if (start < 0 || start > self.characters.count)
{
print("start index \(start) out of bounds")
return ""
}
else if end < 0 || end > self.characters.count
{
print("end index \(end) out of bounds")
return ""
}
let startIndex = self.characters.index(self.startIndex, offsetBy: start)
let endIndex = self.characters.index(self.startIndex, offsetBy: end)
let range = startIndex..<endIndex
return self.substring(with: range)
}
func substring(start: Int, location: Int) -> String
{
if (start < 0 || start > self.characters.count)
{
print("start index \(start) out of bounds")
return ""
}
else if location < 0 || start + location > self.characters.count
{
print("end index \(start + location) out of bounds")
return ""
}
let startIndex = self.characters.index(self.startIndex, offsetBy: start)
let endIndex = self.characters.index(self.startIndex, offsetBy: start + location)
let range = startIndex..<endIndex
return self.substring(with: range)
}
}
And it will be more simple:
let substring = myNSString.substringWithRange(0, location: 3)

Related

How to remove element from a String with Int index

I'm trying to count identical elements in two strings by comparing them in Int range. I solved the issue of subscripting, but I'm now getting an "extra" element. Here's my code:
func getResult(s: String, k: Int, stringGoal: String) -> Int {
var identiticalSymbols = 0
var deletionsLimit = k
var string = s
if string.count <= 19, deletionsLimit <= 9{
for i in 0...string.count-1 {
if string[i] == stringGoal[i] {
identiticalSymbols += i
}
else {
string.remove(at: String.Index(utf16Offset: i, in: string))
deletionsLimit -= 1
}
}
}
return identiticalSymbols
}
}
extension String {
subscript(_ i: Int) -> String {
let idx1 = index(startIndex, offsetBy: i)
return String(self[idx1..<endIndex])
}
subscript (r: Range<Int>) -> String {
let start = index(startIndex, offsetBy: r.lowerBound)
let end = index(startIndex, offsetBy: r.upperBound)
return String(self[start ..< end])
}
}
My input:
let result = getResult(s: "agdd", k: 4, stringGoal: "gdd")
s is initial string, k is deletion limit and goalString is string for comparison.
I'm getting 6 identical symbols instead of 3
I have this code but I'm not using the k, I'm counting the repetitions and remove the repetitions that I already count.
func getRepetitions(firstString: String, comparativeString: String) -> Int {
var repetitions = 0
var comparativeStringName = Array(comparativeString)
for character in firstString {
if comparativeStringName.contains(character),
let index = comparativeStringName.firstIndex(of: character){
comparativeStringName.remove(at: index)
repetitions += 1
}
}
return repetitions
}
It helped me.
func getResult(s: String, k: Int, stringGoal: String) -> Int {
var identiticalSymbols = 0
var deletionsLimit = k
var string = s
if string.count <= 19, deletionsLimit <= 9{
for i in 0...string.count-1 {
if string[i] == stringGoal[i] {
identiticalSymbols += 1
}
else {
string.remove(at: String(string[i]).startIndex)
deletionsLimit -= 1
}
}
}
return identiticalSymbols
}
}
extension String {
var length: Int {
return count
}
subscript (i: Int) -> String {
return self[i ..< i + 1]
}
func substring(fromIndex: Int) -> String {
return self[min(fromIndex, length) ..< length]
}
func substring(toIndex: Int) -> String {
return self[0 ..< max(0, toIndex)]
}
subscript (r: Range<Int>) -> String {
let range = Range(uncheckedBounds: (lower: max(0, min(length, r.lowerBound)),
upper: min(length, max(0, r.upperBound))))
let start = index(startIndex, offsetBy: range.lowerBound)
let end = index(start, offsetBy: range.upperBound - range.lowerBound)
return String(self[start ..< end])
}
}

Type 'MatchedValue' does not conform to protocol 'Decodable'

I have a struct that must conform to Codable protocol.
However, I get the error:
Type 'MatchedValue' does not conform to protocol 'Decodable'**
How can I make String.Index conform to Codable?
Thanks
struct MatchedValue: Codable {
let value: String
let range: Range<String.Index>
}
Try using Int instead of String.Index.
First, extensions to get the position of an element or string as Int and the ability to use integer ranges:
extension StringProtocol {
func distance(of element: Element) -> Int? { firstIndex(of: element)?.distance(in: self) }
func distance<S: StringProtocol>(of string: S) -> Int? { range(of: string)?.lowerBound.distance(in: self) }
func substring(with range: Range<Int>) -> String? {
guard range.lowerBound >= 0 && range.upperBound <= self.count else { return nil }
let lowerBoundStringIndex = self.index(self.startIndex, offsetBy: range.lowerBound)
let upperBoundStringIndex = self.index(lowerBoundStringIndex, offsetBy: range.upperBound - range.lowerBound)
return String(self[lowerBoundStringIndex..<upperBoundStringIndex])
}
subscript(r: Range<Int>) -> String? { substring(with: r) }
func substring(with range: ClosedRange<Int>) -> String? {
guard range.lowerBound >= 0 && range.upperBound < self.count else { return nil }
if range.lowerBound == range.upperBound { return "" }
let lowerBoundStringIndex = self.index(self.startIndex, offsetBy: range.lowerBound)
let upperBoundStringIndex = self.index(lowerBoundStringIndex, offsetBy: range.upperBound + 1 - range.lowerBound)
return String(self[lowerBoundStringIndex..<upperBoundStringIndex])
}
subscript(r: ClosedRange<Int>) -> String? { substring(with: r) }
}
extension Collection {
func distance(to index: Index) -> Int { distance(from: startIndex, to: index) }
}
extension String.Index {
func distance<S: StringProtocol>(in string: S) -> Int { string.distance(to: self) }
}
Now you can use this new implementation:
let letters = "My string"
letters.count // 9
// get range
let lowerBound: Int? = letters.distance(of: "M")
let upperBound: Int? = letters.distance(of: "g")
let intRange: Range<Int> = lowerBound!..<upperBound!
let intClosedRange: ClosedRange<Int> = lowerBound!...upperBound!
// get substring
letters.substring(with: intRange) // "My strin"
letters.substring(with: intClosedRange) // "My string"
// or
letters[intRange] // "My strin"
letters[intClosedRange] // "My string"
I also include a comparison using String.Index and other tests.
// For comparison purposes only
let lowerIndex = letters.firstIndex(of: "M")
let upperIndex = letters.firstIndex(of: "g")
let range: Range<String.Index> = lowerIndex!..<upperIndex!
let closedRange: ClosedRange<String.Index> = lowerIndex!...upperIndex!
letters[range] // "My strin"
letters[closedRange] // "My string"
// Additional implementation tests
letters.substring(with: 3...5) // "str"
letters.substring(with: 3..<5) // "st"
letters.substring(with: 0...9) // nil
letters.substring(with: 0..<9) // "My string"
letters.substring(with: 2...2) // ""
letters.substring(with: 2..<2) // ""
Here is my
gist.

Cannot increment beyond endIndex

I'm looking for the "Swift 3" way of handling an error where I try to increment the position of a string to an out of bounds index. I have an extension that looks like the following:
extension String {
func substring(from: Int) -> String {
let fromIndex = index(from: from)
return substring(from: fromIndex)
}
}
In implementation code, I have a loop which periodically takes chunks of a string and moves the index further in the string. My problem is I'm not sure what the Swift 3 way is of handling "End of String, do not proceed if we've reached the end"
Implementation code is something as trivial as this:
myStr = myStr.substring(from: pos + 1)
if pos + 1 is the end of the string, it shouldn't error out, but should instead just exit/return from my loop. What's the best way of doing that?
You can write something like this
extension String {
func substring(from offset: Int) -> String {
let fromIndex = index(self.startIndex, offsetBy: offset)
return substring(from: fromIndex)
}
}
Examples
"Hello world".substring(from: 0) // "Hello world"
"Hello world".substring(from: 1) // "ello world"
"Hello world".substring(from: 2) // "llo world"
What does happen if you pass the wrong param?
Something like this will generate a fatal error.
"Hello world".substring(from: 12)
fatal error: cannot increment beyond endIndex
You can make you code safer adding a guard statement like this
extension String {
func substring(from: Int) -> String? {
guard from < self.characters.count else { return nil }
let fromIndex = index(self.startIndex, offsetBy: from)
return substring(from: fromIndex)
}
}
You can use the index(_, offsetBy:, limitedBy:) method
to ensure that the index is not advanced beyond the end index:
extension String {
func substring(from: Int) -> String? {
guard let fromIndex = index(startIndex, offsetBy: from, limitedBy: endIndex) else {
return nil
}
return substring(from: fromIndex)
}
}
extension String {
func substring(from index: Int) -> String {
guard index < characters.count else { return "" }
return substring(from: characters.index(startIndex, offsetBy: index))
}
}
"12345".substring(from: 3) // "45"
"12345".substring(from: 9) // ""
Alternatively, you might want to return nil if index is out of bounds when you change the function's return type to String?

Swift3 & Xcode8: ’subscript' is unavailable: cannot subscript String with a CountableClosedRange<Int>,

Error 1:
When I am trying get the stringValue from Metadata shows above error in Swift3:
let myMetadata: AVMetadataMachineReadableCodeObject = metadataObjects[0] as! AVMetadataMachineReadableCodeObject
// take out the system and check-digits
let myBarcode = myMetadata.stringValue[1...11] //error
Error 2:
In extensions of String I write these to get right(x) and left(x) function to get substring:
extension String {
// length of string
var length: Int {
return self.characters.count
}
// right(x) and left(x) function to get substring
func right(_ i: Int) -> String?
{
return self[self.length-i ... self.length-1 ] //error
}
func left(_ i: Int) -> String?
{
return self[0 ... i-1] //error
}
}
Use this extension for the countable closed range [0...4] subscripting
extension String {
subscript (r: CountableClosedRange<Int>) -> String {
get {
let startIndex = self.index(self.startIndex, offsetBy: r.lowerBound)
let endIndex = self.index(startIndex, offsetBy: r.upperBound - r.lowerBound)
return self[startIndex...endIndex]
}
}
}
or a safer version which checks the bounds and returns nil rather than an out-of-range exception:
extension String {
subscript (r: CountableClosedRange<Int>) -> String? {
get {
guard r.lowerBound >= 0, let startIndex = self.index(self.startIndex, offsetBy: r.lowerBound, limitedBy: self.endIndex),
let endIndex = self.index(startIndex, offsetBy: r.upperBound - r.lowerBound, limitedBy: self.endIndex) else { return nil }
return self[startIndex...endIndex]
}
}
}
Swift 4 change: You need to create a new string from the result
return String(self[startIndex...endIndex])
I took inspiration from #vadian's answer and created a set of (Swift 4) extensions that make pulling substrings trivially easy. These do not bounds check, which is generally my preference since I shouldn't be deferring sanity checking to lower level utilities like these.
extension String {
subscript (_ index: Int) -> String {
return String(self[self.index(startIndex, offsetBy: index)])
}
subscript (_ range: CountableRange<Int>) -> String {
let lowerBound = index(startIndex, offsetBy: range.lowerBound)
let upperBound = index(startIndex, offsetBy: range.upperBound)
return String(self[lowerBound..<upperBound])
}
subscript (_ range: CountableClosedRange<Int>) -> String {
let lowerBound = index(startIndex, offsetBy: range.lowerBound)
let upperBound = index(startIndex, offsetBy: range.upperBound)
return String(self[lowerBound...upperBound])
}
subscript (_ range: CountablePartialRangeFrom<Int>) -> String {
return String(self[index(startIndex, offsetBy: range.lowerBound)...])
}
subscript (_ range: PartialRangeUpTo<Int>) -> String {
return String(self[..<index(startIndex, offsetBy: range.upperBound)])
}
subscript (_ range: PartialRangeThrough<Int>) -> String {
return String(self[...index(startIndex, offsetBy: range.upperBound)])
}
}

Swift: easy way to substring?

I have a string:
myString = "mystring"
I would simply like to get the first 5 characters
which is the easiest way to do that in Swift?
Correct answer from Choppin, but if you want to do it in the pure swift way (without casting to NS String :
myString = myString.substringToIndex(advance(myString.startIndex, 5))
let substring: String = (myString as NSString).substringToIndex(5)
Use these extensions:
Swift 2.3
extension String
{
func substringFromIndex(index: Int) -> String
{
if (index < 0 || index > self.characters.count)
{
print("index \(index) out of bounds")
return ""
}
return self.substringFromIndex(self.startIndex.advancedBy(index))
}
func substringToIndex(index: Int) -> String
{
if (index < 0 || index > self.characters.count)
{
print("index \(index) out of bounds")
return ""
}
return self.substringToIndex(self.startIndex.advancedBy(index))
}
func substringWithRange(start: Int, end: Int) -> String
{
if (start < 0 || start > self.characters.count)
{
print("start index \(start) out of bounds")
return ""
}
else if end < 0 || end > self.characters.count
{
print("end index \(end) out of bounds")
return ""
}
let range = Range(start: self.startIndex.advancedBy(start), end: self.startIndex.advancedBy(end))
return self.substringWithRange(range)
}
func substringWithRange(start: Int, location: Int) -> String
{
if (start < 0 || start > self.characters.count)
{
print("start index \(start) out of bounds")
return ""
}
else if location < 0 || start + location > self.characters.count
{
print("end index \(start + location) out of bounds")
return ""
}
let range = Range(start: self.startIndex.advancedBy(start), end: self.startIndex.advancedBy(start + location))
return self.substringWithRange(range)
}
}
Swift 3
extension String
{
func substring(from index: Int) -> String
{
if (index < 0 || index > self.characters.count)
{
print("index \(index) out of bounds")
return ""
}
return self.substring(from: self.characters.index(self.startIndex, offsetBy: index))
}
func substring(to index: Int) -> String
{
if (index < 0 || index > self.characters.count)
{
print("index \(index) out of bounds")
return ""
}
return self.substring(to: self.characters.index(self.startIndex, offsetBy: index))
}
func substring(start: Int, end: Int) -> String
{
if (start < 0 || start > self.characters.count)
{
print("start index \(start) out of bounds")
return ""
}
else if end < 0 || end > self.characters.count
{
print("end index \(end) out of bounds")
return ""
}
let startIndex = self.characters.index(self.startIndex, offsetBy: start)
let endIndex = self.characters.index(self.startIndex, offsetBy: end)
let range = startIndex..<endIndex
return self.substring(with: range)
}
func substring(start: Int, location: Int) -> String
{
if (start < 0 || start > self.characters.count)
{
print("start index \(start) out of bounds")
return ""
}
else if location < 0 || start + location > self.characters.count
{
print("end index \(start + location) out of bounds")
return ""
}
let startIndex = self.characters.index(self.startIndex, offsetBy: start)
let endIndex = self.characters.index(self.startIndex, offsetBy: start + location)
let range = startIndex..<endIndex
return self.substring(with: range)
}
}
Usage:
let myString = "mystring"
let substring = myString.substringToIndex(5)