How to take NSRange in swift? - ios

I am very much new to swift language. I am performing some business logic which needs to take NSRange from given String.
Here is my requirement,
Given Amount = "144.44"
Need NSRange of only cent part i.e. after "."
Is there any API available for doing this?

You can do a regex-based search to find the range:
let str : NSString = "123.45"
let rng : NSRange = str.range("(?<=[.])\\d*$", options: .RegularExpressionSearch)
Regular expression "(?<=[.])\\d*$" means "zero or more digits following a dot character '.' via look-behind, all the way to the end of the string $."

If you want a substring from a given string you can use componentsSeparatedByString
Example :
var number: String = "144.44";
var numberresult= number.componentsSeparatedByString(".")
then you can get components as :
var num1: String = numberresult [0]
var num2: String = numberresult [1]
hope it help !!

Use rangeOfString and substringFromIndex:
let string = "123.45"
if let index = string.rangeOfString(".") {
let cents = string.substringFromIndex(index.endIndex)
print("\(cents)")
}

Another version that uses Swift Ranges, rather than NSRange
Define the function that returns an optional Range:
func centsRangeFromString(str: String) -> Range<String.Index>? {
let characters = str.characters
guard let dotIndex = characters.indexOf(".") else { return nil }
return Range(dotIndex.successor() ..< characters.endIndex)
}
Which you can test with:
let r = centsRangeFromString(str)
// I don't recommend force unwrapping here, but this is just an example.
let cents = str.substringWithRange(r!)

Related

Swift String operation not working

I am trying to read the string from a Label and remove the last character form it.
This is how I am trying:
#IBAction func del(sender: UIButton) {
let str = telephone.text!;
let newstr = str.remove(at: str.index(before: str.endIndex))
telephone.text = newstr;
}
When I run, I get an error:
"String" does not have a member named "remove"
Can someone help me figure out the problem?
Just started learning swift :(
remove(at:) mutates the receiver which must therefore be a variable
string:
var str = telephone.text!
str.remove(at: str.index(before: str.endIndex))
telephone.text = str
Alternatively use substring(to:), which returns the new string
instead of modifying the receiver:
let str = telephone.text!
let newstr = str.substring(to: str.index(before: str.endIndex))
telephone.text = newstr
remove is defined as follows:
public mutating func remove(at i: String.Index) -> Character
See the mutating modifier? That means it mutates the instance on which the method is called. In your case, the instance is str, a constant. Since constants cannot be mutated, the code does not compile.
And since remove returns the removed character,
let newstr = str.remove(at: str.index(before: str.endIndex))
here newstr will not be storing the string with the last character removed.
You should rewrite the method like this:
telephone.text!.remove(at: telephone.text!.index(before: telephone.text!.endIndex))
You can use:
let idx = str.index(before: str.endIndex) // compute the index
let s = str.substring(to: idx) // get the substring

Remove special characters from the string

I am trying to use an iOS app to dial a number. The problem is that the number is in the following format:
po placeAnnotation.mapItem.phoneNumber!
"‎+1 (832) 831-6486"
I want to get rid of some special characters and I want the following:
832-831-6486
I used the following code but it did not remove anything:
let charactersToRemove = CharacterSet(charactersIn: "()+-")
var telephone = placeAnnotation.mapItem.phoneNumber?.trimmingCharacters(in: charactersToRemove)
Any ideas?
placeAnnotation.mapItem.phoneNumber!.components(separatedBy: CharacterSet.decimalDigits.inverted)
.joined()
Here you go!
I tested and works well.
If you want something similar to CharacterSet with some flexibility, this should work:
let phoneNumber = "1 (832) 831-6486"
let charsToRemove: Set<Character> = Set("()+-".characters)
let newNumberCharacters = String(phoneNumber.characters.filter { !charsToRemove.contains($0) })
print(newNumberCharacters) //prints 1 832 8316486
I know the question is already answered, but to format phone numbers in any way one could use a custom formatter like below
class PhoneNumberFormatter:Formatter
{
var numberFormat:String = "(###) ### ####"
override func string(for obj: Any?) -> String? {
if let number = obj as? NSNumber
{
var input = number as Int64
var output = numberFormat
while output.characters.contains("#")
{
if let range = output.range(of: "#", options: .backwards)
{
output = output.replacingCharacters(in: range, with: "\(input % 10)")
input /= 10
}
else
{
output.replacingOccurrences(of: "#", with: "")
}
}
return output
}
return nil
}
func string(from number:NSNumber) -> String?
{
return string(for: number)
}
}
let phoneNumberFormatter = PhoneNumberFormatter()
//Digits will be filled backwards in place of hashes. It is easy change the custom formatter in anyway
phoneNumberFormatter.numberFormat = "###-##-##-##-##"
phoneNumberFormatter.string(from: 18063783889)
Swift 3
func removeSpecialCharsFromString(_ str: String) -> String {
struct Constants {
static let validChars = Set("1234567890-".characters)
}
return String(str.characters.filter { Constants.validChars.contains($0) })
}
To Use
let str : String = "+1 (832) 831-6486"
let newStr : String = self.removeSpecialCharsFromString(str)
print(newStr)
Note: you can add validChars which you want in string after operation perform.
If you have the number and special character in String format the use following code to remove special character
let numberWithSpecialChar = "1800-180-0000"
let actulNumber = numberWithSpecialChar.components(separatedBy: CharcterSet.decimalDigit.inverted).joined()
Otherwise, If you have the characters and special character in String format the use following code to remove special character
let charactersWithSpecialChar = "A man, a plan, a cat, a ham, a yak, a yam, a hat, a canal-Panama!"
let actulString = charactersWithSpecialChar.components(separatedBy: CharacterSet.letters.inverted).joined(separator: " ")
NSString *str = #"(123)-456-7890";
NSLog(#"String: %#", str);
// Create character set with specified characters
NSMutableCharacterSet *characterSet =
[NSMutableCharacterSet characterSetWithCharactersInString:#"()-"];
// Build array of components using specified characters as separtors
NSArray *arrayOfComponents = [str componentsSeparatedByCharactersInSet:characterSet];
// Create string from the array components
NSString *strOutput = [arrayOfComponents componentsJoinedByString:#""];
NSLog(#"New string: %#", strOutput);

How to get value from point(a b) swift

I have this kind of string: "POINT(101.650577657408 3.1653186153213)".
Anyone know how can I get the first and second value of POINT from this String?
You can easily spit the string using componentsSeparatedByString function.
let myStr = "POINT(101.650577657408 3.1653186153213)"
let characterSet = NSCharacterSet(charactersInString: "( )")
var splitString = myStr.componentsSeparatedByCharactersInSet(characterSet)
print(splitString[0])
print(splitString[1])
print(splitString[2])
The above only works if you have the complete one String.
Although the NSCharacterSet solution is correct but here is another solution using the most powerful regex.
var error: NSError?
// Initialise the regex for a float value
let regex: NSRegularExpression = NSRegularExpression(pattern: "(\\d*\\.\\d*)", options: NSRegularExpressionOptions.CaseInsensitive, error: &error)!
// Matches array contains all the match found for float in given string
let matches: NSArray = regex.matchesInString(str as String, options: NSMatchingOptions.ReportProgress, range: NSMakeRange(0, str.length))
// You can easily get all values by enumeration
for match in matches {
println(str.substringWithRange(match.range))
}
The benefit of this solution is it will scan all the float values and will also work in case of pattern got changed.
Try this, this will work for your string
let myStr = "POINT(101.650577657408 3.1653186153213)"
let strWithout_POINT_openingBrace = myStr.stringByReplacingOccurrencesOfString("POINT(", withString: "")//"101.650577657408 3.1653186153213)"
let strWithout_closingBrace = strWithout_POINT_openingBrace.stringByReplacingOccurrencesOfString(")", withString: "")//"101.650577657408 3.1653186153213"
//now you have only space between two values
//so split string by space
let arrStringValues = strWithout_closingBrace.componentsSeparatedByString(" ");//["101.650577657408","3.1653186153213"]
print(arrStringValues[0]);//first value "101.650577657408"
print(arrStringValues[1]);//second value "3.1653186153213"

Using character delimiters to find and highlight text in Swift

I previously developed an android app that served as a reference guide to users. It used a sqlite database to store the information. The database stores UTF-8 text without formatting (i.e. bold or underlined)
To highlight what sections of text required formatting I enclosed them using delimiter tokens specifically $$ as this does not appear in the database as information. Before displaying the text to the user I wrote a method to find these delimiters and add formatting to the text contained within them and delete the delimiters. so $$foo$$ became foo.
My java code for this is as follows:
private static CharSequence boldUnderlineText(CharSequence text, String token) {
int tokenLen = token.length();
int start = text.toString().indexOf(token) + tokenLen;
int end = text.toString().indexOf(token, start);
while (start > -1 && end > -1)
{
SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(text);
//add the formatting required
spannableStringBuilder.setSpan(new UnderlineSpan(), start, end, 0);
spannableStringBuilder.setSpan(new StyleSpan(Typeface.BOLD), start, end, 0);
// Delete the tokens before and after the span
spannableStringBuilder.delete(end, end + tokenLen);
spannableStringBuilder.delete(start - tokenLen, start);
text = spannableStringBuilder;
start = text.toString().indexOf(token, end - tokenLen - tokenLen) + tokenLen;
end = text.toString().indexOf(token, start);
}
return text;
}
I have recreated my app in Swift for iOS and it is complete apart from showing the correct formatting. It appears that Swift treats strings differently from other languages.
So far I have tried using both NSString and String types for my original unformatted paragraph and get manage to get the range, start and end index of the first delimiter:
func applyFormatting2(noFormatString: NSString, delimiter: String){
let paragraphLength: Int = noFormatString.length //length of paragraph
let tokenLength: Int = delimiter.characters.count //length of token
let rangeOfToken = noFormatString.rangeOfString(formatToken) //range of the first delimiter
let startOfToken = rangeOfToken.toRange()?.startIndex //start index of first delimiter
let endOfToken = rangeOfToken.toRange()?.endIndex //end index of first delimiter
var startOfFormatting = endOfToken //where to start the edit (end index of first delimiter)
}
OR
func applyFormatting(noFormatString: String, token: String){
let paragraphLength: Int = noFormatString.characters.count
let tokenLength: Int = token.characters.count //length of the $$ Token (2)
let rangeOfToken = noFormatString.rangeOfString(formatToken) //The range of the first instance of $$ in the no format string
let startOfToken = rangeOfToken?.startIndex //the starting index of the found range for the found instance of $$
let endOfToken = rangeOfToken?.endIndex //the starting index of the found range for the found instance of $$
var startOfFormatting = endOfToken
}
I appreciate this code is verbose and has pointless variables but it helps me think though my code when I'm working out a problem.
I am currently struggling to workout how to find the second/closing delimiter. I want to search through the string from a specific index as I did in Java using the line
int end = text.toString().indexOf(token, start);
however I cannot work out how to do this using ranges.
Can anyone help me out with either how to correctly identify where the closing delimiter is or how to complete the code block to format all the required text?
Thanks
Aldo
How about using NSRegularExpression?
public extension NSMutableAttributedString {
func addAttributes(attrs: [String : AnyObject], delimiter: String) throws {
let escaped = NSRegularExpression.escapedPatternForString(delimiter)
let regex = try NSRegularExpression(pattern:"\(escaped)(.*?)\(escaped)", options: [])
var offset = 0
regex.enumerateMatchesInString(string, options: [], range: NSRange(location: 0, length: string.characters.count)) { (result, flags, stop) -> Void in
guard let result = result else {
return
}
let range = NSRange(location: result.range.location + offset, length: result.range.length)
self.addAttributes(attrs, range: range)
let replacement = regex.replacementStringForResult(result, inString: self.string, offset: offset, template: "$1")
self.replaceCharactersInRange(range, withString: replacement)
offset -= (2 * delimiter.characters.count)
}
}
}
Here is how you call it.
let string = NSMutableAttributedString(string:"Here is some $$bold$$ text that should be $$emphasized$$")
let attributes = [NSFontAttributeName: UIFont.boldSystemFontOfSize(15)]
try! string.addAttributes(attributes, delimiter: "$$")
The iOS way of doing this is with NS[Mutable]AttributedStrings. You set dictionaries of attributes on text ranges. These attributes include font weights, sizes, colors, line spacing, etc.

StringBetweenString function

I need to get substring between two strings from my text. For example, I have text "http://google.com" and I want to get substring between "://" and ".".
I don't know, how I can do that.
I try to use regular expressions, but I think, it's bad way.
A couple of options:
Regular expressions work well. See ICU User Guide: Regular Expressions
Example:
let us = "http://google.com"
let range = us.rangeOfString("(?<=://)[^.]+(?=.)", options:.RegularExpressionSearch)
if range != nil {
let found = us.substringWithRange(range!)
println("found: \(found)") // found: google
}
Notes:
(?<=://) means preceded by ://
[^.]+ means any characters except .
(?=.) means followed by .
NSScanner is also a good method. See Apple's NSScanner Class Reference
Example:
let us = "http://google.com"
let scanner = NSScanner(string:us)
var scanned: NSString?
if scanner.scanUpToString("://", intoString:nil) {
scanner.scanString("://", intoString:nil)
if scanner.scanUpToString(".", intoString:&scanned) {
let result: String = scanned as String
println("result: \(result)") // result: google
}
}
You can use the regular Expression
://.+.
it matches to
://google.
in this code:
var yourURL: NSString = "http://google.com" // this is your input and could be any URL
var regex: NSRegularExpression = NSRegularExpression.regularExpressionWithPattern("://.+\\.", options: NSRegularExpressionOptions.fromMask(UInt(0)), error: nil) // need double backspace because of backspace in String is \\ not \
var needleRange = regex.rangeOfFirstMatchInString(yourURL, options:NSMatchingOptions.Anchored, range: NSMakeRange(0, yourURL.length))
var needle: NSString = yourURL.substringWithRange(needleRange)
Now you can remove the first 3 symbols and the last one and you got
google
with this code:
import Foundation
var halfURL: NSString = "://google."
var prefix: NSString = "://"
var suffix: NSString = "."
var needleRange: NSRange = NSMakeRange(prefix.length, halfURL.length - prefix.length - suffix.length)
var needle: NSString = halfURL.substringWithRange(needleRange)
// needle is now 'google'
If your input is a valid URL, you can take advantage of the NSURL class to do the parsing for you:
var result : NSString?
let input = "http://test.com/blabla"
// Parse the string; might fail
let url : NSURL? = NSURL(string: input)
// Get the host part of the URL ("test.com")
let host = url?.host
// Split it up at the dots.
let hostParts = host?.componentsSeparatedByString(".")
// Assign the first part of the hostname if we were successful up to here.
if hostParts?.count > 0 {
result = hostParts![0]
}
Bonus: ignore "www":
if hostParts?.count > 0 {
if (hostParts![0] == "www" && hostParts!.count > 1) {
result = hostParts![1]
} else {
result = hostParts![0]
}
}
For swift 3.0:
let us = "http://example.com"
let range = us.range(of:"(?<=://)[^.]+(?=.com)", options:.regularExpression)
if range != nil {
let found = us.substring(with: range!)
print("found: \(found)") // found: example
}

Resources