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

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.

Related

Convert to string an Any value

This fails (Non-nominal type 'Any' cannot be extended)
extension Any {
func literal() -> String {
if let booleanValue = (self as? Bool) {
return String(format: (booleanValue ? "true" : "false"))
}
else
if let intValue = (self as? Int) {
return String(format: "%d", intValue)
}
else
if let floatValue = (self as? Float) {
return String(format: "%f", floatValue)
}
else
if let doubleValue = (self as? Double) {
return String(format: "%f", doubleValue)
}
else
{
return String(format: "<%#>", self)
}
}
}
as I would like to use it in a dictionary (self) to xml string factory like
extension Dictionary {
// Return an XML string from the dictionary
func xmlString(withElement element: String, isFirstElement: Bool) -> String {
var xml = String.init()
if isFirstElement { xml.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n") }
xml.append(String(format: "<%#>\n", element))
for node in self.keys {
let value = self[node]
if let array: Array<Any> = (value as? Array<Any>) {
xml.append(array.xmlString(withElement: node as! String, isFirstElemenet: false))
}
else
if let dict: Dictionary<AnyHashable,Any> = (value as? Dictionary<AnyHashable,Any>) {
xml.append(dict.xmlString(withElement: node as! String, isFirstElement: false))
}
else
{
xml.append(String(format: "<%#>", node as! CVarArg))
xml.append((value as Any).literal
xml.append(String(format: "</%#>\n", node as! CVarArg))
}
}
xml.append(String(format: "</%#>\n", element))
return xml.replacingOccurrences(of: "&", with: "&amp", options: .literal, range: nil)
}
}
I was trying to reduce the code somehow, as the above snippet is repeated a few times in a prototype I'm building but this is not the way to do it (a working copy with the snippet replicated works but ugly?).
Basically I want to generate a literal for an Any value - previously fetched from a dictionary.
It seems like you can't add extensions to Any. You do have some other options though - either make it a function toLiteral(value: Any) -> String, or what is probably a neater solution; use the description: String attribute which is present on all types that conform to CustomStringConvertible, which includes String, Int, Bool, and Float - your code would be simplified down to just xml.append(value.description). You then just have make a simple implementation for any other types that you might get.
Ok, finally got this working. First the preliminaries: each of your objects needs to have a dictionary() method to marshal itself. Note: "k.###" are struct static constants - i.e., k.name is "name", etc. I have two objects, a PlayItem and a PlayList:
class PlayItem : NSObject {
var name : String = k.item
var link : URL = URL.init(string: "http://")!
var time : TimeInterval
var rank : Int
var rect : NSRect
var label: Bool
var hover: Bool
var alpha: Float
var trans: Int
var temp : String {
get {
return link.absoluteString
}
set (value) {
link = URL.init(string: value)!
}
}
func dictionary() -> Dictionary<String,Any> {
var dict = Dictionary<String,Any>()
dict[k.name] = name
dict[k.link] = link.absoluteString
dict[k.time] = time
dict[k.rank] = rank
dict[k.rect] = NSStringFromRect(rect)
dict[k.label] = label ? 1 : 0
dict[k.hover] = hover ? 1 : 0
dict[k.alpha] = alpha
dict[k.trans] = trans
return dict
}
}
class PlayList : NSObject {
var name : String = k.list
var list : Array <PlayItem> = Array()
func dictionary() -> Dictionary<String,Any> {
var dict = Dictionary<String,Any>()
var items: [Any] = Array()
for item in list {
items.append(item.dictionary())
}
dict[k.name] = name
dict[k.list] = items
return dict
}
}
Note any value so marshal has to be those legal types for a dictionary; it helps to have aliases so in the PlayItem a "temp" is the string version for the link url, and its getter/setter would translate.
When needed, like the writeRowsWith drag-n-drop tableview handler, I do this:
func tableView(_ tableView: NSTableView, writeRowsWith rowIndexes: IndexSet, to pboard: NSPasteboard) -> Bool {
if tableView == playlistTableView {
let objects: [PlayList] = playlistArrayController.arrangedObjects as! [PlayList]
var items: [PlayList] = [PlayList]()
var promises = [String]()
for index in rowIndexes {
let item = objects[index]
let dict = item.dictionary()
let promise = dict.xmlString(withElement: item.className, isFirstElement: true)
promises.append(promise)
items.append(item)
}
let data = NSKeyedArchiver.archivedData(withRootObject: items)
pboard.setPropertyList(data, forType: PlayList.className())
pboard.setPropertyList(promises, forType:NSFilesPromisePboardType)
pboard.writeObjects(promises as [NSPasteboardWriting])
}
else
{
let objects: [PlayItem] = playitemArrayController.arrangedObjects as! [PlayItem]
var items: [PlayItem] = [PlayItem]()
var promises = [String]()
for index in rowIndexes {
let item = objects[index]
let dict = item.dictionary()
let promise = dict.xmlString(withElement: item.className, isFirstElement: true)
promises.append(promise)
items.append(item)
}
let data = NSKeyedArchiver.archivedData(withRootObject: items)
pboard.setPropertyList(data, forType: PlayList.className())
pboard.setPropertyList(promises, forType:NSFilesPromisePboardType)
pboard.writeObjects(promises as [NSPasteboardWriting])
}
return true
}
What makes this happen are these xmlString extensions and the toLiteral function - as you cannot extend "Any":
func toLiteral(_ value: Any) -> String {
if let booleanValue = (value as? Bool) {
return String(format: (booleanValue ? "1" : "0"))
}
else
if let intValue = (value as? Int) {
return String(format: "%d", intValue)
}
else
if let floatValue = (value as? Float) {
return String(format: "%f", floatValue)
}
else
if let doubleValue = (value as? Double) {
return String(format: "%f", doubleValue)
}
else
if let stringValue = (value as? String) {
return stringValue
}
else
if let dictValue: Dictionary<AnyHashable,Any> = (value as? Dictionary<AnyHashable,Any>)
{
return dictValue.xmlString(withElement: "Dictionary", isFirstElement: false)
}
else
{
return ((value as AnyObject).description)
}
}
extension Array {
func xmlString(withElement element: String, isFirstElemenet: Bool) -> String {
var xml = String.init()
xml.append(String(format: "<%#>\n", element))
self.forEach { (value) in
if let array: Array<Any> = (value as? Array<Any>) {
xml.append(array.xmlString(withElement: "Array", isFirstElemenet: false))
}
else
if let dict: Dictionary<AnyHashable,Any> = (value as? Dictionary<AnyHashable,Any>) {
xml.append(dict.xmlString(withElement: "Dictionary", isFirstElement: false))
}
else
{
xml.append(toLiteral(value))
}
}
xml.append(String(format: "<%#>\n", element))
return xml
}
}
extension Dictionary {
// Return an XML string from the dictionary
func xmlString(withElement element: String, isFirstElement: Bool) -> String {
var xml = String.init()
if isFirstElement { xml.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n") }
xml.append(String(format: "<%#>\n", element))
for node in self.keys {
let value = self[node]
if let array: Array<Any> = (value as? Array<Any>) {
xml.append(array.xmlString(withElement: node as! String, isFirstElemenet: false))
}
else
if let dict: Dictionary<AnyHashable,Any> = (value as? Dictionary<AnyHashable,Any>) {
xml.append(dict.xmlString(withElement: node as! String, isFirstElement: false))
}
else
{
xml.append(String(format: "<%#>", node as! CVarArg))
xml.append(toLiteral(value as Any))
xml.append(String(format: "</%#>\n", node as! CVarArg))
}
}
xml.append(String(format: "</%#>\n", element))
return xml
}
func xmlHTMLString(withElement element: String, isFirstElement: Bool) -> String {
let xml = self.xmlString(withElement: element, isFirstElement: isFirstElement)
return xml.replacingOccurrences(of: "&", with: "&amp", options: .literal, range: nil)
}
}
This continues another's solution, the toLiteral() suggestion above, in hopes it helps others.
Enjoy.

Swift 4 'substring(from:)' is deprecated: Please use String slicing subscript with a 'partial range from' operator

i've just converted my little app but i've found this error:
'substring(from:)' is deprecated: Please use String slicing subscript with a 'partial range from' operator
my code is:
let dateObj = dateFormatterFrom.date(from: dateStringa)
if dateObj != nil {
cell.detailTextLabel?.text = dateFormatterTo.string(from:(dateObj!))
} else {
let index = thisRecord.pubDate.index(thisRecord.pubDate.startIndex, offsetBy: 5)
cell.detailTextLabel?.text = thisRecord.pubDate.substring(from: index)
}
Follow the below example to fix this warning:
Supporting examples for Swift 3, 4 and 5.
let testStr = “Test Teja”
let finalStr = testStr.substring(to: index) // Swift 3
let finalStr = String(testStr[..<index]) // Swift 4
let finalStr = testStr.substring(from: index) // Swift 3
let finalStr = String(testStr[index...]) // Swift 4
//Swift 3
let finalStr = testStr.substring(from: index(startIndex, offsetBy: 3))
//Swift 4 and 5
let reqIndex = testStr.index(testStr.startIndex, offsetBy: 3)
let finalStr = String(testStr[..<reqIndex])
//**Swift 5.1.3 - usage of index**
let myStr = "Test Teja == iOS"
let startBound1 = String.Index(utf16Offset: 13, in: myStr)
let finalStr1 = String(myStr[startBound1...])// "iOS"
let startBound2 = String.Index(utf16Offset: 5, in: myStr)
let finalStr2 = String(myStr[startBound2..<myStr.endIndex]) //"Teja == iOS"
In place of substring use suffix. Use like below :
cell.detailTextLabel?.text = String(thisRecord.pubDate.suffix(from: index))
It means you should use the new partial range operator as your upperBound:
let str = "Hello World !!!"
if let index = str.range(of: "Hello ")?.upperBound {
let string = String(str[index...]) // "World !!!"
}
In your case
cell.detailTextLabel?.text = String(thisRecord.pubDate[index...]))
In Swift 5, it is:
extension String {
func index(from: Int) -> Index {
return self.index(startIndex, offsetBy: from)
}
func substring(from: Int) -> String {
let fromIndex = index(from: from)
return String(self[fromIndex...])
}
func substring(to: Int) -> String {
let toIndex = index(from: to)
return String(self[..<toIndex])
}
func substring(with r: Range<Int>) -> String {
let startIndex = index(from: r.lowerBound)
let endIndex = index(from: r.upperBound)
return String(self[startIndex..<endIndex])
}
}
Most of my strings have A-Za-z and 0-9 content. No need for difficult
Index handling. This extension of String is based on the familiar LEFT / MID and RIGHT functions.
extension String {
// LEFT
// Returns the specified number of chars from the left of the string
// let str = "Hello"
// print(str.left(3)) // Hel
func left(_ to: Int) -> String {
return "\(self[..<self.index(startIndex, offsetBy: to)])"
}
// RIGHT
// Returns the specified number of chars from the right of the string
// let str = "Hello"
// print(str.left(3)) // llo
func right(_ from: Int) -> String {
return "\(self[self.index(startIndex, offsetBy: self.length-from)...])"
}
// MID
// Returns the specified number of chars from the startpoint of the string
// let str = "Hello"
// print(str.left(2,amount: 2)) // ll
func mid(_ from: Int, amount: Int) -> String {
let x = "\(self[self.index(startIndex, offsetBy: from)...])"
return x.left(amount)
}
}
If you wish to get substring with specific offset without upper bound do the following:
let index = thisRecord.pubDate.index(thisRecord.pubDate.startIndex, offsetBy: 5)
cell.detailTextLabel?.text = String(thisRecord.pubDate[index...]
This way you create a new String object from your existing String thisRecord.pubDate taking anything from specified index to the end index of original String.
str[..<index]
str[index...]
The code above is "partial range from"
Look at this How can I use String slicing subscripts in Swift 4?

range function and crash in swift 3

My below code crashes:
func getrange(_ from: Int, length: Int) -> Range<String.Index>? {
guard let fromU16 = utf16.index(utf16.startIndex, offsetBy: from, limitedBy: utf16.endIndex), fromU16 != utf16.endIndex else {
return nil ----->crashes here
}
let toU16 = utf16.index(fromU16, offsetBy: length, limitedBy: utf16.endIndex) ?? utf16.endIndex
guard let from = String.Index(fromU16, within: self),
let to = String.Index(toU16, within: self) else { return nil }
return from ..< to
}
This code is crashing with swift 3 migration.
Can someone help debugging the issue.
Below is the sequence of events:
//input for below function is: text “123456789”, string “0”, nsrange = location =9, length=0
1) function 1
static func numericText(_ text: String, replacedBy string: String, in nsrange: NSRange) -> String {
guard let range = text.range(for: nsrange) else {
//assertionFailure("Should never reach here")
return text.numericString()
}
// Apply Replacement String to the textField text and extract only the numeric values
return text.replacingCharacters(in: range, with: string)
.numericString()
}
2) function 2
func range(for nsrange: NSRange) -> Range<String.Index>? {
return range(nsrange.location, length: nsrange.length)
}
3) function 3
func range(_ from: Int, length: Int) -> Range<String.Index>? {
guard let fromU16 = utf16.index(utf16.startIndex, offsetBy: from, limitedBy: utf16.endIndex), fromU16 != utf16.endIndex else {
return nil
}
let toU16 = utf16.index(fromU16, offsetBy: length, limitedBy: utf16.endIndex) ?? utf16.endIndex
guard let from = String.Index(fromU16, within: self),
let to = String.Index(toU16, within: self) else { return nil }
return from ..< to
}
Sorry, I didn't update during the weekend.
I reviewed your question.
I can implement your function 1:
extension String {
func getrange(_ from: Int, length: Int) -> Range<String.Index>? {
guard let fromU16 = utf16.index(utf16.startIndex, offsetBy: from, limitedBy: utf16.endIndex), fromU16 != utf16.endIndex else {
return nil
}
let toU16 = utf16.index(fromU16, offsetBy: length, limitedBy: utf16.endIndex) ?? utf16.endIndex
guard let from = String.Index(fromU16, within: self),
let to = String.Index(toU16, within: self) else { return nil }
return from ..< to
}
}
But I cant implement your function 2, is that converted to Swift3 syntax yet?
My question is this,
Below is the sequence of events:
//input for below function is: text “123456789”, string “0”, nsrange = location =9, length=0
your input, your location shouldn't be 9. As your string length is 9, the max location your can replace should be 8?
Just replacing utf with unicodeScalars in the code fixed the issue.

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)])
}
}