I have a question. I write tests for a mobile app. And at this moment, I compare the prices in different currencies like Pound, Euro, India, etc. A possible comparison should be "now £1.678,95". It's no problem for me to cut the "now", to cut the whitespace - short, to get the string in a possible Int or Double formation. BUT now I'm in France. In France the formation is "maintenant 2 500,00 €". No problem with the "maintenant", no problem with the whitespace outside the price and no problem with "€".
BUT there is a space IN the price between 2 and 500. If I run my test, I have only the "2" the rest is gone!
How can I do it, that the whitespace should not cut here. It should backspaced from "2 500,00" to "2500,00".
Hope you have an idea :) Thanks!
My code at this moment is:
var firstPrice = XCUIApplication().collectionViews.cells.element(boundBy: 0).staticTexts.element(boundBy: 2).label
firstPrice = firstPrice.replacingOccurrences(of: "£", with: "")
firstPrice = firstPrice.replacingOccurrences(of: "€", with: "")
firstPrice = firstPrice.replacingOccurrences(of: "₹", with: "")
let firstPriceArray = firstPrice.components(separatedBy: .whitespaces).filter { !$0.isEmpty }
firstPrice = firstPriceArray[1]
let firstPriceTrimmedDouble = firstPrice.toDouble(with: SiteIDHelper.locale(from: SiteIDHelper.SiteID(rawValue: Int(sideIDS))!))!
print(firstPriceTrimmedDouble)
Tough, because you don't know the locale of the string. 1234 Euro can be written as € 1,234.00 in English style, or 1.234,00 € in French and German styles. (Euro is very common in England too).
From the limited examples you provided, you can remove the first word, then deleting all spaces, commas, dots and currency signs from the remaining before converting it to Double:
let priceString = "maintenant 2 500,00 €"
let unwanted = " ,.£€₹"
var doubleValue : Double?
if let range = priceString.range(of: " ") {
let chars = priceString[range.upperBound..<priceString.endIndex]
.characters.filter({ !unwanted.characters.contains($0) })
doubleValue = Double(String(chars))
}
// run your asserts here
Not really clear what you are after... but to remove all whitespaces, try this:
var price: String = ...
while let range = price.rangeOfCharacter(from: .whitespaces) {
price.removeSubrange(range)
}
Related
I am trying to identify keys word in user entry to search for, so I thought of filtering out some parts of speech in order to extract key words to query in my database .
currently I use the code below to replace the word "of" from a string
let rawString = "I’m jealous of my parents. I’ll never have a kid as cool as theirs, one who is smart, has devilishly good looks, and knows all sorts of funny phrases."
var filtered = self.rawString.replacingOccurrences(of: "of", with: "")
what I want to do now is extend it to replace all preposition in a string.
What I was thinking of doing is creating a huge list of known prepositions like
let prepositions = ["in","through","after","under","beneath","before"......]
and then spliting the string by white space with
var WordList : [String] = filtered.components(separatedBy: " ")
and then looping through the wordlist to find a prepositional match and deleting it. Creating the list will be ugly and might not be efficient for my code.
What is the best way to detect and delete prepositions from a string?
Use NaturalLanguage:
import NaturalLanguage
let text = "The ripe taste of cheese improves with age."
let tagger = NLTagger(tagSchemes: [.lexicalClass])
tagger.string = text
let options: NLTagger.Options = [.omitPunctuation, .omitWhitespace]
var newSentence = [String]()
tagger.enumerateTags(in: text.startIndex..<text.endIndex, unit: .word, scheme: .lexicalClass, options: options) { tag, tokenRange in
guard let tag = tag, tag != .preposition else { return true }
newSentence.append("\(text[tokenRange])")
return true
}
print("Input: \(text)")
print("Output: \(newSentence.joined(separator: " "))")
This prints:
Input: The ripe taste of cheese improves with age.
Output: The ripe taste cheese improves age
Notice the two prepositions of and with are removed. My approach also removes the punctuation; you can adjust this with the .omitPunctuation option.
var newString = rawString
.split(separator: " ")
.filter{ !prepositions.contains(String($0))}
.joined(separator: " ")
This question already has answers here:
How should I remove all the leading spaces from a string? - swift
(31 answers)
Closed 4 years ago.
i'm getting my contacts number locally from my mobile. There are some number in which there are white spaces between numbers. I'm trying to remove the white spaces from the number but it isn't working,this is how i'm removing the white spaces,
let number = contact.phoneNumbers.first?.value.stringValue
let formattedString = number?.replacingOccurrences(of: " ", with: "")
print(formattedString)
But when i print this is what i got in the console,
+92 324 4544783
The white sapces are still coming how can i remove that?
Here you go: source
For trimming white spaces from both ends, you can use:
let number = contact.phoneNumbers.first?.value.stringValue
let formattedString = number.trimmingCharacters(in: .whitespacesAndNewlines)
print(formattedString)
For removing whitespaces that might be inside the string, use:
let x = "+92 300 7681277"
let result = x.replacingOccurrences(of: " ", with: "")
You should get:
result = +923007681277
EDIT: I updated my answer.
let number = contact.phoneNumbers.first?.value.stringValue
let number_without_space = number.components(separatedBy: .whitespaces).joined()
print(number_without_space) //use this variable wherever you want to use
joined() is a function it will join your string after removing spaces like this
let str = "String Name"
str.components(separatedBy: .whitespaces).joined()
extension to remove spaces
extension String
{
func removeSpaces() -> String {
return components(separatedBy: .whitespaces).joined()
}
}
I am given a string like 4eysg22yl3kk and my output should be like this:
foureysgtweny-twoylthreekk or if I am given 0123 it should be output as one hundred twenty-three. So basically, as I scan the string, I need to convert numbers to string.
I do not know how to implement this in Swift as I iterate through the string? Any idea?
You actually have two basic problems.
The first is convert a "number" to "spelt out" value (ie 1 to one). This is actually easy to solve, as NumberFormatter has a spellOut style property
let formatter = NumberFormatter()
formatter.numberStyle = .spellOut
let text = formatter.string(from: NSNumber(value: 1))
which will result in "one", neat.
The other issue though, is how to you separate the numbers from the text?
While I can find any number of solutions for "extract" numbers or characters from a mixed String, I can't find one which return both, split on their boundaries, so, based on your input, we'd end up with ["4", "eysg", "22", "yl", "3", "kk"].
So, time to role our own...
func breakApart(_ text: String, withPattern pattern: String) throws -> [String]? {
do {
let regex = try NSRegularExpression(pattern: "[0-9]+", options: .caseInsensitive)
var previousRange: Range<String.Index>? = nil
var parts: [String] = []
for match in regex.matches(in: text, options: [], range: NSRange(location: 0, length: text.count)) {
guard let range = Range(match.range, in: text) else {
return nil
}
let part = text[range]
if let previousRange = previousRange {
let textRange = Range<String.Index>(uncheckedBounds: (lower: previousRange.upperBound, upper: range.lowerBound))
parts.append(String(text[textRange]))
}
parts.append(String(part))
previousRange = range
}
if let range = previousRange, range.upperBound != text.endIndex {
let textRange = Range<String.Index>(uncheckedBounds: (lower: range.upperBound, upper: text.endIndex))
parts.append(String(text[textRange]))
}
return parts
} catch {
}
return nil
}
Okay, so this is a little "dirty" (IMHO), but I can't seem to think of a better approach, hopefully someone will be kind enough to provide some hints towards one ;)
Basically what it does is uses a regular expression to find all the groups of numbers, it then builds an array, cutting the string apart around the matching boundaries - like I said, it's crude, but it gets the job done.
From there, we just need to map the results, spelling out the numbers as we go...
let formatter = NumberFormatter()
formatter.numberStyle = .spellOut
let value = "4eysg22yl3kk"
if let parts = try breakApart(value, withPattern: pattern) {
let result = parts.map { (part) -> String in
if let number = Int(part), let text = formatter.string(from: NSNumber(value: number)) {
return text
}
return part
}.joined(separator: " ")
print(result)
}
This will end up printing four eysg twenty-two yl three kk, if you don't want the spaces, just get rid of separator in the join function
I did this in Playgrounds, so it probably needs some cleaning up
I was able to solve my question without dealing with anything extra than converting my String to an array and check char by char. If I found a digit I was saving it in a temp String and as soon as I found out the next char is not digit, I converted my digit to its text.
let inputString = Array(string.lowercased())
this might be a basic question but I am having a hard time not including the - in the second
var title1 = "I will be part of string 1 - I am part of string 2"
let end = title1.range(of: "-", options: .backwards)?.lowerBound
let firstPartRange = title1.startIndex..<end!
var secondPart = title1.substring(with: firstPartRange) // Gives me "I will be part of string 1" which is correct
title1.substring(from: end!) // however this guy gives me "- I am part of string 2" & I only want to get "I am part of string 2" without the space and dash in front
Can I shift the range or change it's lowerBound somehow?. I know I can user separate component by function here but would like to learn how to offset my range
You just need to get the index after end or offset it by 2. Note that you should also make sure it doesn't pass the end index using the method index(theIndex, offsetBy: n, limitedBy: endIndex)
let title1 = "I will be part of string 1 - I am part of string 2"
if let end = title1.range(of: "-", options: .backwards)?.lowerBound {
let firstPartRange = title1.startIndex..<end
let secondPart = title1.substring(with: firstPartRange) // "I will be part of string 1 "
title1.substring(from: title1.index(after: end)) // " I am part of string 2"
// or to offset it by two you should also make sure it doesn't pass the end index
title1.substring(from: title1.index(end, offsetBy: 2, limitedBy: title1.endIndex) ?? title1.endIndex) // "I am part of string 2"
}
You are looking for index(_:offsetBy:). This is a method of the original string, like this:
var title1 = "I will be part of string 1 - I am part of string 2"
let end = title1.range(of: "-", options: .backwards)!.lowerBound
let ix = title1.index(end, offsetBy: 2)
title1.substring(from: ix) // "I am part of string 2"
You can separate the contents of string by using components(separatedBy: String) method which will return you with array of separated strings then you can remove white spaces from the last element.
var title1 = "I will be part of string 1 - I am part of string 2"
print(title1.components(separatedBy: "-").last!.trimmingCharacters(in: .whitespacesAndNewlines))
it will give you the desired result
"I am part of string 2"
Hope it helps!
You could use the components function and include the spaces in the separator:
title1.components(separatedBy:" - ")
As #matt suggest, you are looking for index(_:offsetBy:)
A little bit different approach using Swift standard library only (no Foundation)
let str = "I will be part of string 1 - I am part of string 2"
let parts = str.characters.split(separator: "-").map(String.init)
if you would like to trim all extra spaces
let partsTrimmed = parts.map {
$0.characters.split(separator: " ").map(String.init).joined(separator: " ")
}
I'm using this code to find the NSRange and text content of the string contents of a NSTextField.
nstext.enumerateSubstringsInRange(NSMakeRange(0, nstext.length),
options: NSStringEnumerationOptions.ByWords, usingBlock: {
(substring, substringRange, _, _) -> () in
//Do something with substring and substringRange
}
The problem is that NSStringEnumerationOptions.ByWords ignores punctuation, so that
Stop clubbing, baby seals
becomes
"Stop" "clubbing" "baby" "seals"
not
"Stop" "clubbing," "baby" "seals
If all else fails I could just check the characters before or after a given word and see if they are on the exempted list (where would I find which characters .ByWords exempts?); but there must be a more elegant solution.
How can I find the NSRanges of a set of words, from a string which includes the punctuation as part of the word?
You can use componentsSeparatedByString instead
var arr = nstext.componentsSeparatedByString(" ")
Output :
"Stop" "clubbing," "baby" "seals
Inspired by Richa's answer, I used componentsSeparatedByString(" "). I had to add a bit of code to make it work for me, since I wanted the NSRanges from the output. I also wanted it to still work if there were two instances of the same word - e.g. 'please please stop clubbing, baby seals'.
Here's what I did:
var words: [String] = []
var ranges: [NSRange] = []
//nstext is a String I converted to a NSString
words = nstext.componentsSeparatedByString(" ")
//apologies for the poor naming
var nstextLessWordsWeHaveRangesFor = nstext
for word in words
{
let range:NSRange = nstextLessWordsWeHaveRangesFor.rangeOfString(word)
ranges.append(range)
//create a string the same length as word so that the 'ranges' don't change in the future (if I just replace it with "" then the future ranges will be wrong after removing the substring)
var fillerString:String = ""
for var i=0;i<word.characters.count;++i{
fillerString = fillerString.stringByAppendingString(" ")
}
nstextLessWordsWeHaveRangesFor = nstextLessWordsWeHaveRangesFor.stringByReplacingCharactersInRange(range, withString: fillerString)
}