I'm stuck help. You have to use strings, but I haven't really found a logical way to make this work well.
var letters = ["Zero","One","Two","Three","Four","Five","Six","Seven","Eight","Nine","Ten"]
var str:String
print("Enter a number from 0 to 10: ")
str = readLine()!
print (letters[0])
...
print("Enter a number from 0 to 10: ")
str = readLine()!
print (letters[10])
Maybe this api is similar but not exactly what you need.
https://developer.apple.com/documentation/foundation/numberformatter/style/spellout
let formatter: NumberFormatter = {
let nf = NumberFormatter()
nf.numberStyle = .spellOut
nf.locale = Locale(identifier: "en_US")
return nf
}()
extension Numeric {
var spelledOut: String? {
return formatter.string(for: self)
}
}
let one = 1.spelledOut
print(one) //->one
print(25.spelledOut) //->twenty-five
print(1.5.spelledOut) //->one point five
https://developer.apple.com/forums/thread/121448
You can do it like this with String extension
extension String {
func wordToInteger() -> Int {
let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = .spellOut
return numberFormatter.number(from: self.lowercased()) as? Int ?? 0
}
}
Use like this
let letters = ["Zero","One","Two","Three","Four","Five","Six","Seven","Eight","Nine","Ten"]
print(letters[10].wordToInteger()) // In your Case
print("Three".wordToInteger())
Output
Basicly I want something like this,
NSString* foobar(NSString *input) {
// say input is "1"
NSString *string = #"0123456789";
NSString *anotherString = #"零一二三四五六七八九";
NSRange range = [string rangeOfString:input];
// return "一" here
return [anotherString substringWithRange:range];
}
I tried the same stuff in Swift,
func foobar(input: String) -> String {
// say input is "1"
let string = "0123456789"
let range = string.range(of: input, options: .anchored)
let result = anotherString[range!]
// return "012" here
return String(result)
}
why?
And how can I achieve this?
String (or generally, collection) indices must only be used with the collection that they were created with. In order to find the same positions in another string, the indices must be converted to (integer) offsets and back to indices of the target string:
func foobar(input: String) -> String? {
let s1 = "0123456789"
let s2 = "😀一二三四五六七八九";
guard let range = s1.range(of: input) else {
return nil
}
let pos = s1.distance(from: s1.startIndex, to: range.lowerBound)
let len = s1.distance(from: range.lowerBound, to: range.upperBound)
guard
let lo = s2.index(s2.startIndex, offsetBy: pos, limitedBy: s2.endIndex),
let hi = s2.index(lo, offsetBy: len, limitedBy: s2.endIndex)
else {
return nil
}
return String(s2[lo..<hi])
}
print(foobar(input: "1") as Any) // Optional("一")
print(foobar(input: "123") as Any) // Optional("一二三")
print(foobar(input: "124") as Any) // nil
Your Objective-C code works as long as all characters in the string consume a single UTF-16 code unit (because that is what NSRange counts). It will not work correctly emojis, flags, and other characters which are represented as UTF-16 surrogate pairs, e.g. with
NSString *anotherString = #"😀一二三四五六七八九";
Another approach is converting strings to array of characters
func find(_ str: Character) {
let firstArr = Array("0123456789")
let secondArr = Array("零一二三四五六七八九")
guard let index = firstArr.firstIndex(of: str) else {
print("Not found")
return
}
print(firstArr[index]) // 2
print(secondArr[index]) // 二
}
find("2")
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?
I'm setting the text on a textview and then calling this method of the UITextView extension in order to create links out of the words that are hashtags and mentions (Swift 3)
extension UITextView {
func resolveHashTags(font: UIFont = UIFont.systemFont(ofSize: 17.0)){
if let text = self.text {
let words:[String] = text.components(separatedBy: " ")
let attrs = [ NSFontAttributeName : font ]
let attrString = NSMutableAttributedString(string: text, attributes:attrs)
for word in words {
if (word.characters.count > 1 && ((word.hasPrefix("#") && word[1] != "#") || (word.hasPrefix("#") && word[1] != "#"))) {
let matchRange = text.range(of: word)
let newWord = String(word.characters.dropFirst())
if let matchRange = matchRange {
attrString.addAttribute(NSLinkAttributeName, value: "\(word.hasPrefix("#") ? "hashtag:" : "mention:")\(newWord)", range: text.NSRangeFromRange(range: matchRange))
}
}
}
self.attributedText = attrString
}
}
}
My issue is very simple. I have no way to create a link for something like this "helloworld#hello" simply because my word does not have a prefix of "#"
Another scenario I can't figure out is when the user puts multi hashtags together for example "hello world, how are you? #success#moments#connect" as this would all be considered 1 hashtag with the current logic when it should be 3 different links.
How do i correct? thank you
func resolveHashTags(text : String) -> NSAttributedString{
var length : Int = 0
let text:String = text
let words:[String] = text.separate(withChar: " ")
let hashtagWords = words.flatMap({$0.separate(withChar: "#")})
let attrs = [NSFontAttributeName : UIFont.systemFont(ofSize: 17.0)]
let attrString = NSMutableAttributedString(string: text, attributes:attrs)
for word in hashtagWords {
if word.hasPrefix("#") {
let matchRange:NSRange = NSMakeRange(length, word.characters.count)
let stringifiedWord:String = word
attrString.addAttribute(NSLinkAttributeName, value: "hash:\(stringifiedWord)", range: matchRange)
}
length += word.characters.count
}
return attrString
}
To separate words I used a string Extension
extension String {
public func separate(withChar char : String) -> [String]{
var word : String = ""
var words : [String] = [String]()
for chararacter in self.characters {
if String(chararacter) == char && word != "" {
words.append(word)
word = char
}else {
word += String(chararacter)
}
}
words.append(word)
return words
}
}
func textViewDidChange(_ textView: UITextView) {
textView.attributedText = resolveHashTags(text: textView.text)
textView.linkTextAttributes = [NSForegroundColorAttributeName : UIColor.red]
}
I hope this is what you are looking for. Tell me if it worked out for you.
If you're willing to use a 3rd party library, you could try using Mustard (disclaimer: I'm the author).
You could match hashtag tokens using this tokenizer:
struct HashtagTokenizer: TokenizerType, DefaultTokenizerType {
// start of token is identified by '#'
func tokenCanStart(with scalar: UnicodeScalar) -> Bool {
return scalar == UnicodeScalar(35) // ('35' is scalar value for the # character)
}
// all remaining characters must be letters
public func tokenCanTake(_ scalar: UnicodeScalar) -> Bool {
return CharacterSet.letters.contains(scalar)
}
}
Which can then be used to match the hashtags in the text:
let hashtags = "hello world, how are you? #success#moments#connect".tokens(matchedWith: HashtagTokenizer())
// hashtags.count -> 3
// hashtags[0].text -> "#success"
// hashtags[0].range -> 26..<34
// hashtags[1].text -> "#moments"
// hashtags[1].range -> 34..<42
// hashtags[2].text -> "#connect"
// hashtags[2].range -> 42..<50
The array returned is an array of tokens, where each one contains a text property of the matched text, and a range property of the range of that matched text in the original string that you can use to create a link on the text view.
I have an array of NSattributedstring. I want to get the index of a string in the array. I am using the following code.
let textToSearch = "My name is Amrit"
let index = find(myArray, textToSearch)
myArray is an array of NsattributedString. As both the types of array and textTosearch are different.
indexArray = ["1. THE OPENING","2. THE COW","3. THE FAMILY OF IMRAN","4. WOMEN","5. THE FEAST","6. LIVESTOCK","7. THE HEIGHTS","8. BATTLE GAINS","9. REPENTANCE","10. JONAH","11. HUD","12. JOSEPH","13. THUNDER","14. ABRAHAM","15. AL-HIJR","16. THE BEE","17. THE NIGHT JOURNEY","18. THE CAVE","19. MARY","20. TA HA","21. THE PROPHETS","22. THE PILGRIMAGE","23. THE BELIEVERS","24. LIGHT","25. THE DIFFERENTIATOR","26. THE POETS","27. THE ANTS","28. THE STORY","29. THE SPIDER","30. THE BYZANTINES","31. LUQMAN","32. BOWING DOWN IN WORSHIP","33. THE JOINT FORCES","34. SHEBA","35. THE CREATOR","36. YA SIN","37. RANGED IN ROWS","38. SAD","39. THE THRONGS","40. THE FORGIVER","41. [VERSES] MADE DISTINCT","42. CONSULTATION","43. ORNAMENTS OF GOLD","44. SMOKE","45. KNEELING","46. THE SAND DUNES","47. MUHAMMAD","48. TRIUMPH","49. THE PRIVATE ROOMS","50. QAF","51. SCATTERING [WINDS]","52. THE MOUNTAIN","53. THE STAR","54. THE MOON","55. THE LORD OF MERCY","56. THAT WHICH IS COMING","57. IRON","58. THE DISPUTE","59. THE GATHERING [OF FORCES]","60. WOMEN TESTED","61. SOLID LINES","62. THE DAY OF CONGREGATION","63. THE HYPOCRITES","64. MUTUAL NEGLECT","65. DIVORCE","66. PROHIBITION","67. CONTROL","68. THE PEN","69. THE INEVITABLE HOUR","70. THE WAYS OF ASCENT","71. NOAH","72. THE JINN","73. ENFOLDED","74. WRAPPED IN HIS CLOAK","75. THE RESURRECTION","76. MAN","77. [WINDS] SENT FORTH","78. THEANNOUNCEMENT","79. THE FORCEFUL CHARGERS","80. HE FROWNED","81. SHROUDED IN DARKNESS","82. TORN APART","83. THOSE WHO GIVE SHORT MEASURE","84. RIPPED APART","85. THE TOWERING CONSTELLATIONS","86. THE NIGHT-COMER","87. THE MOST HIGH","88. THE OVERWHELMING EVENT","89. DAYBREAK","90. THE CITY","91. THE SUN","92. THE NIGHT","93. THE MORNING BRIGHTNESS","94. RELIEF","95. THE FIG","96. THE CLINGING FORM","97. THE NIGHT OF GLORY","98. CLEAR EVIDENCE","99. THE EARTHQUAKE","100. THE CHARGING STEEDS","101. THE CRASHING BLOW","102. STRIVING FOR MORE","103. THE DECLINING DAY","104. THE BACKBITER","105. THE ELEPHANT","106. QURAYSH","107. COMMON KINDNESSES","108. ABUNDANCE","109. THE DISBELIEVERS","110. HELP","111. PALM FIBRE","112. PURITY [OF FAITH]","113. DAYBREAK","114. PEOPLE"]
if let rtfPath = NSBundle.mainBundle().URLForResource("quaran3", withExtension: "rtf") {
let attributedStringWithRtf = NSMutableAttributedString(fileURL: rtfPath, options: [NSDocumentTypeDocumentAttribute:NSRTFTextDocumentType], documentAttributes: nil, error: nil)!
var lengthOfRtf = attributedStringWithRtf.length
divideFactor = Int(lengthOfRtf/endIndex)
println(divideFactor)
self.updateTextFont(attributedStringWithRtf) (valueFactor: divideFactor) (totalRange: lengthOfRtf)
self.getTheIndexNumber(attributedStringWithRtf) (valueFactor: divideFactor)
}
func updateTextFont(mystring:NSMutableAttributedString) (valueFactor:Int) (totalRange : Int) {
let screenSizeMain: CGRect = UIScreen.mainScreen().bounds
let myAttriText:NSMutableAttributedString = mystring.mutableCopy() as! NSMutableAttributedString
myAttriText.beginEditing()
myAttriText.enumerateAttributesInRange(NSMakeRange(0, myAttriText.length), options: NSAttributedStringEnumerationOptions.Reverse) { (attribute, range, stop) -> Void in
var mutableAttributes = NSDictionary(dictionary: attribute)
var font:UIFont = mutableAttributes.objectForKey(NSFontAttributeName) as! UIFont
var newFont:UIFont = font.fontWithSize(font.pointSize)
if DeviceType.IS_IPAD
{
newFont = font.fontWithSize(font.pointSize+7)
}
var fontProperties:UIFontDescriptor = font.fontDescriptor()
let sizeNumber:Float = fontProperties.fontAttributes()[UIFontDescriptorSizeAttribute] as! Float
myAttriText.addAttribute(NSFontAttributeName, value: newFont, range: range)
}
for var i=0; i <= valueFactor; i++ {
// if valueFactor*
if startIndex == 885819 {
}
//let checkCurrentRange = valueFactor*endIndex
let exactEndIndex : Int = endIndex
if (totalRange - startIndex) < endIndex
{
endIndex = totalRange - startIndex
let rangeFinal = NSMakeRange(startIndex, endIndex)
var nsTextFinal = myAttriText.attributedSubstringFromRange(rangeFinal)
pageText.append(nsTextFinal)
endIndex = exactEndIndex
return
}
let range = NSMakeRange(startIndex, endIndex)
var nsText = myAttriText.attributedSubstringFromRange(range)
for index in endIndex..<endIndex+100
{
let rangeNew = NSMakeRange(endIndex + startIndex-1,1)
var checkSpace = myAttriText.attributedSubstringFromRange(rangeNew)
let stirngNew = checkSpace.string
if stirngNew == " "
{
break;
}
else
{
endIndex++
}
}
let rangeFinal = NSMakeRange(startIndex, endIndex)
var nsTextFinal = myAttriText.attributedSubstringFromRange(rangeFinal)
pageText.append(nsTextFinal)
println(startIndex)
startIndex = startIndex + endIndex
endIndex = exactEndIndex
}
myAttriText.endEditing()
}
func visibleRangeOfTextView(textView: NSAttributedString) -> NSRange {
return NSMakeRange(startIndex, endIndex)
}
func getTheIndexNumber(attribSring:NSMutableAttributedString) (valueFactor:Int) //-> NSMutableArray
{
for index in 0..<indexArray.count {
let text = indexArray.objectAtIndex(index) as! NSString
var lengthOfRtf = attribSring.length
var textNew = attribSring.attributedSubstringFromRange(NSMakeRange(0, lengthOfRtf))
var stirngNew : NSMutableString = attribSring.mutableString.mutableCopy() as! NSMutableString
// println(stirngNew)
var range: NSRange = (stirngNew as NSString).rangeOfString(text as String)
var checkSpace = attribSring.attributedSubstringFromRange(range)
let stirngNewCheck = checkSpace.string
let pageIndex = (range.location / endIndex)
indeArryInt.addObject(pageIndex)
}
}
You can try this:
let index = myArray.indexOf { $0.string == textToSearch }
This returns an Int?, the first index where a match is found. If there's no match, it will return nil.
If you are using Swift 1.2 you will need to map array of NSAttributedString to String array so find function can be called with correct values
let index = find(myArray.map({ attributedString in
return attributedString.string
}), textToSearch)
#ZoffDino answer would work like a charm in Swift 2.0