I am looking for a simple way to remove the 4 characters in the tilesColored String "ment" from the shuffledWord1.
var word1: String = "employment"
var shuffledWord1: String = "melpyoemtn"
var tilesColored: String = "ment"
var characters = Array(tilesColored) // gives ["m","e","n","t"]
let newWord1 = word1.StringByReplacingOccurencesOfString("\(characters[0])", withString:"") // gives "elpyoetn"
stringByReplacingOccurencesOfString only allows 1 character to be checked and removes BOTH m's, so how can I check against all 4 and only remove ONE instance of each to return "melpyo"?
Thanks in advance for any help possible
Swift 3+ version with better performance than the previous top answers. (Because we don't separate into arrays with substrings, which all would need seperate allocations.)
This here just works on the unicode scalar level. You can paste it right into a playground.
import Foundation
extension String {
func removeCharacters(from forbiddenChars: CharacterSet) -> String {
let passed = self.unicodeScalars.filter { !forbiddenChars.contains($0) }
return String(String.UnicodeScalarView(passed))
}
func removeCharacters(from: String) -> String {
return removeCharacters(from: CharacterSet(charactersIn: from))
}
}
let str = "n1o d2i3g4i5t6s!!!789"
let t1 = str.removeCharacters(from: CharacterSet.decimalDigits.inverted)
print(t1) // will print: 123456789
let t2 = str.removeCharacters(from: "0123456789")
print(t2) // will print: no digits!!!
Swift 3 version of Macondo2Seattle's answer, which, I think, is the most elegant solution.
extension String {
func removing(charactersOf string: String) -> String {
let characterSet = CharacterSet(charactersIn: string)
let components = self.components(separatedBy: characterSet)
return components.joined(separator: "")
}
}
Swift 5:
var phrase = "The rain in Spain stays mainly in the plain."
let vowels: Set<Character> = ["a", "e", "i", "o", "u"]
phrase.removeAll(where: { vowels.contains($0) })
// phrase == "Th rn n Spn stys mnly n th pln."
extension String {
func removeCharacters(characters: String) -> String {
let characterSet = NSCharacterSet(charactersInString: characters)
let components = self.componentsSeparatedByCharactersInSet(characterSet)
let result = components.joinWithSeparator("")
return result
}
}
Swift 2.0:
extension String {
func stringByRemovingOnce(chars: String) -> String {
var cs = Set(chars.characters)
let fd = characters.filter { c in
cs.remove(c).map { _ in false } ?? true
}
return String(fd)
}
}
"melpyoemtn".stringByRemovingOnce("ment") // "lpyoem"
Swift 1.2:
extension String {
func stringByRemovingOnce(chars: String) -> String {
var cs = Set(chars)
let fd = filter(self) { c in
cs.remove(c).map { _ in false } ?? true
}
return String(fd)
}
}
"melpyoemtn".stringByRemovingOnce("ment") // "lpyoem"
Related
here's a part of my code :
let separator = anyWord.indexOf("-")!
if (separator >= 0) {
let res = anyWord[anyWord.characters.index(after: separator)..<anyWord.endIndex] //get an error
//some code
}
I get an error in 'let res' part - Type 'String!' has no subscript members
if I do :
let separator = anyWord.indexOf("-")!
let subStartIndex = anyWord.characters.index(after: separator)
the extension to String :
extension String {
public func indexOf(_ char: Character) -> Int! {
if let idx = self.characters.index(of: char) {
return self.characters.distance(from: self.startIndex, to: idx)
}
return Const.INVALID_VALUE
}
I get error :
String may not be indexed with 'Int", it has variable size elements
You are thinking too complicated, it's pretty easy in Swift 3 using range(of and upperBound
let anyWord = "asdghf-fkgjh"
if let separator = anyWord.range(of:"-") {
let res = anyWord.substring(from: separator.upperBound)
//some code
}
Cast it to string
let test: String
test = "Test-Word"
if let separatorWord = anyWord.range(of: "-")
{
let word = anyWord.substring(from: anyWord.index(after:
separatorWord.lowerBound))
print(word)
}
I like 'pure' swift solution ( no Foundation required )
let anyWord = "asdghf-fkgjh-blablabla--bla"
anyWord.characters.split(separator: "-").forEach { print( String($0)) }
it prints
asdghf
fkgjh
blablabla
bla
If my main array is ["Hello","Bye","Halo"], and I'm searching for "lo", it will filter the array only to ["Hello", "Halo"].
This is what I've tried:
let matchingTerms = filter(catalogNames) {
$0.rangeOfString(self.txtField.text!, options: .CaseInsensitiveSearch) != nil
}
It throws
Type of expression is ambiguous without more context
Any suggestions?
Use contains instead:
let arr = ["Hello","Bye","Halo"]
let filtered = arr.filter { $0.contains("lo") }
print(filtered)
Output
["Hello", "Halo"]
Thanks to #user3441734 for pointing out that functionality is of course only available when you import Foundation
In Swift 3.0
let terms = ["Hello","Bye","Halo"]
var filterdTerms = [String]()
func filterContentForSearchText(searchText: String) {
filterdTerms = terms.filter { term in
return term.lowercased().contains(searchText.lowercased())
}
}
filterContentForSearchText(searchText: "Lo")
print(filterdTerms)
Output
["Hello", "Halo"]
Swift 3.1
let catalogNames = [ "Hats", "Coats", "Trousers" ]
let searchCatalogName = "Hats"
let filteredCatalogNames = catalogNames.filter { catalogName in
return catalogName.localizedCaseInsensitiveContains(searchCatalogName)
}
print(filteredCatalogNames)
my try...
let brands = ["Apple", "FB", "Google", "Microsoft", "Amazon"]
let b = brands.filter{(x) -> Bool in
(x.lowercased().range(of: "A".lowercased()) != nil)
}
print(b) //["Apple", "Amazon"]
with help of String extension you can use pure Swift solution (without import Foundation). I didn't check the speed, but it shouldn't be worse as the foundation equivalent.
extension String {
func contains(string: String)->Bool {
guard !self.isEmpty else {
return false
}
var s = self.characters.map{ $0 }
let c = string.characters.map{ $0 }
repeat {
if s.startsWith(c){
return true
} else {
s.removeFirst()
}
} while s.count > c.count - 1
return false
}
}
let arr = ["Hello","Bye","Halo"]
let filtered = arr.filter { $0.contains("lo") }
print(filtered) // ["Hello", "Halo"]
"a".contains("alphabet") // false
"alphabet".contains("") // true
You also need to compare to NSNotFound. The documentation for rangeOfString:options: says:
An NSRange structure giving the location and length in the receiver of the first occurrence of aString, modulo the options in mask. Returns {NSNotFound, 0} if aString is not found or is empty (#"").
import Foundation
let catalogNames = [ "Hats", "Coats", "Trousers" ]
let matchingTerms = catalogNames.filter {
$0.rangeOfString(self.txtField.text!, options: .CaseInsensitiveSearch).location != NSNotFound
}
Swift 5:
Considered below example. Filtering (case insensitive) out data from array 1 and populating 2nd array with that
let data = ["Apple", "Oranges", "Banana", "Grapes"]
var filteredData = [String]()
func filterText(_ text: String?) {
guard let text = text else {return}
filteredData.removeAll()
for element in data {
if element.lowercased().starts(with: text.lowercased()){
filteredData.append(element)
}
}
}
I want this:
var String1 = "Stack Over Flow"
var desiredOutPut = "SOF" // the first Character of each word in a single String (after space)
I know how to get the first character from a string but have no idea what to do this with this problem.
You can try this code:
let stringInput = "First Last"
let stringInputArr = stringInput.components(separatedBy:" ")
var stringNeed = ""
for string in stringInputArr {
stringNeed += String(string.first!)
}
print(stringNeed)
If have problem with componentsSeparatedByString you can try seperate by character space and continue in array you remove all string empty.
Hope this help!
To keep it more elegant I would make an extension for the swift 3.0 String class with the following code.
extension String
{
public func getAcronyms(separator: String = "") -> String
{
let acronyms = self.components(separatedBy: " ").map({ String($0.characters.first!) }).joined(separator: separator);
return acronyms;
}
}
Afterwords you can just use it like this:
let acronyms = "Hello world".getAcronyms();
//will print: Hw
let acronymsWithSeparator = "Hello world".getAcronyms(separator: ".");
//will print: H.w
let upperAcronymsWithSeparator = "Hello world".getAcronyms(separator: ".").uppercased();
//will print: H.W
SWIFT 3
To avoid the crash when there are multiple spaces between words (i.e. John Smith), you can use something like this:
extension String {
func acronym() -> String {
return self.components(separatedBy: .whitespaces).filter { !$0.isEmpty }.reduce("") { $0.0 + String($0.1.characters.first!) }
}
}
If you want to include newlines as well, just replace .whitespaces with .whitespacesAndNewlines.
Or by using .reduce():
let str = "Stack Over Flow"
let desiredOutPut = str
.components(separatedBy: " ")
.reduce("") { $0 + ($1.first.map(String.init) ?? "") }
print(desiredOutPut)
Note that if you're experiencing error:
Cannot invoke 'reduce' with an argument list of type '(String, (_) -> _)
labelForContext.text = self.components(separatedBy: " ").reduce("") { first, next in
(first) + (next.first.map { String($0) } ?? "")
}
You can use the componentsSeparatedByString() method to get an array of strings. Use " " as the separator.
Since you know how to get the first char of a string, now you just do that for each string in the array.
var String1 = "Stack Over Flow"
let arr = String1.componentsSeparatedByString(" ")
var desiredoutput = ""
for str in arr {
if let char = str.characters.first {
desiredoutput += String(char)
}
}
desiredoutput
By the way, the convention for variable names I believe is camel-case with a lowercase letter for the first character, such as "string1" as opposed to "String1"
Here is the changes in swift3
let stringInput = "Stack Overflow"
let stringInputArr = stringInput.components(separatedBy: " ")
var stringNeed = ""
for string in stringInputArr {
stringNeed = stringNeed + String(string.characters.first!)
}
print(stringNeed)
For the sake of completeness this is a solution with very powerful enumerateSubstrings(in:options:_:
let string = "Stack Over Flow"
var result = ""
string.enumerateSubstrings(in: string.startIndex..<string.endIndex, options: .byWords) { (substring, _, _, _) in
if let substring = substring { result += substring.prefix(1) }
}
print(result)
let inputString = "ABC PQR XYZ"
var stringNeed = ""
class something
{
let splits = inputString.components(separatedBy: " ")
for string in splits
{
stringNeed = stringNeed + String(string.first!)
}
print(stringNeed)
}
Here's the version I used for Swift 5.7 and newer
extension String {
func getAcronym() -> String {
let array = components(separatedBy: .whitespaces)
return array.reduce("") { $0 + String($1.first!)}
}
}
For example:
let test = "hello"
let second_string = "world"
I have a string called test, it contains 5 characters.
Then I have another string: var result:String
I want the first 3 characters in result will be the first 3 characters in test and its rest part will be the content in second_string.
Like
result[0...2] = test[0...2]
result[3...7] = second_string[0...4]
//just pseudo code
This is my extension code:
extension String {
var length: Int {
return self.characters.count
}
subscript (i:Int) -> Character{
return self[self.startIndex.advancedBy(i)]
}
subscript (i: Int) -> String {
return String(self[i] as Character)
}
subscript (r: Range<Int>) -> String {
return substringWithRange(Range(start: startIndex.advancedBy(r.startIndex), end: startIndex.advancedBy(r.endIndex)))
}
}
What should I do ?
let test = "hello"
let second_string = "world"
let range = test.startIndex.advancedBy(0)..<test.startIndex.advancedBy(3)
print(test[range] + second_string)
I have a string composed of words, some of which contain punctuation, which I would like to remove, but I have been unable to figure out how to do this.
For example if I have something like
var words = "Hello, this : is .. a string?"
I would like to be able to create an array with
"[Hello, this, is, a, string]"
My original thought was to use something like words.stringByTrimmingCharactersInSet() to remove any characters I didn't want but that would only take characters off the ends.
I thought maybe I could iterate through the string with something in the vein of
for letter in words {
if NSCharacterSet.punctuationCharacterSet.characterIsMember(letter){
//remove that character from the string
}
}
but I'm unsure how to remove the character from the string. I'm sure there are some problems with the way that if statement is set up, as well, but it shows my thought process.
Xcode 11.4 • Swift 5.2 or later
extension StringProtocol {
var words: [SubSequence] {
split(whereSeparator: \.isLetter.negation)
}
}
extension Bool {
var negation: Bool { !self }
}
let sentence = "Hello, this : is .. a string?"
let words = sentence.words // ["Hello", "this", "is", "a", "string"]
String has a enumerateSubstringsInRange() method.
With the .ByWords option, it detects word boundaries and
punctuation automatically:
Swift 3/4:
let string = "Hello, this : is .. a \"string\"!"
var words : [String] = []
string.enumerateSubstrings(in: string.startIndex..<string.endIndex,
options: .byWords) {
(substring, _, _, _) -> () in
words.append(substring!)
}
print(words) // [Hello, this, is, a, string]
Swift 2:
let string = "Hello, this : is .. a \"string\"!"
var words : [String] = []
string.enumerateSubstringsInRange(string.characters.indices,
options: .ByWords) {
(substring, _, _, _) -> () in
words.append(substring!)
}
print(words) // [Hello, this, is, a, string]
This works with Xcode 8.1, Swift 3:
First define general-purpose extension for filtering by CharacterSet:
extension String {
func removingCharacters(inCharacterSet forbiddenCharacters:CharacterSet) -> String
{
var filteredString = self
while true {
if let forbiddenCharRange = filteredString.rangeOfCharacter(from: forbiddenCharacters) {
filteredString.removeSubrange(forbiddenCharRange)
}
else {
break
}
}
return filteredString
}
}
Then filter using punctuation:
let s:String = "Hello, world!"
s.removingCharacters(inCharacterSet: CharacterSet.punctuationCharacters) // => "Hello world"
let charactersToRemove = NSCharacterSet.punctuationCharacterSet().invertedSet
let aWord = "".join(words.componentsSeparatedByCharactersInSet(charactersToRemove))
An alternate way to filter characters from a set and obtain an array of words is by using the array's filter and reduce methods. It's not as compact as other answers, but it shows how the same result can be obtained in a different way.
First define an array of the characters to remove:
let charactersToRemove = Set(Array(".:?,"))
next convert the input string into an array of characters:
let arrayOfChars = Array(words)
Now we can use reduce to build a string, obtained by appending the elements from arrayOfChars, but skipping all the ones included in charactersToRemove:
let filteredString = arrayOfChars.reduce("") {
let str = String($1)
return $0 + (charactersToRemove.contains($1) ? "" : str)
}
This produces a string without the punctuation characters (as defined in charactersToRemove).
The last 2 steps:
split the string into an array of words, using the blank character as separator:
let arrayOfWords = filteredString.componentsSeparatedByString(" ")
last, remove all empty elements:
let finalArrayOfWords = arrayOfWords.filter { $0.isEmpty == false }
NSScaner way:
let words = "Hello, this : is .. a string?"
//
let scanner = NSScanner(string: words)
var wordArray:[String] = []
var word:NSString? = ""
while(!scanner.atEnd) {
var sr = scanner.scanCharactersFromSet(NSCharacterSet(charactersInString: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKMNOPQRSTUVWXYZ"), intoString: &word)
if !sr {
scanner.scanLocation++
continue
}
wordArray.append(String(word!))
}
println(wordArray)