Remove nth character from string - string

I have seen many methods for removing the last character from a string. Is there however a way to remove any old character based on its index?

Here is a safe Swift 4 implementation.
var s = "Hello, I must be going"
var n = 5
if let index = s.index(s.startIndex, offsetBy: n, limitedBy: s.endIndex) {
s.remove(at: index)
print(s) // prints "Hello I must be going"
} else {
print("\(n) is out of range")
}

While string indices aren't random-access and aren't numbers, you can advance them by a number in order to access the nth character:
var s = "Hello, I must be going"
s.removeAtIndex(advance(s.startIndex, 5))
println(s) // prints "Hello I must be going"
Of course, you should always check the string is at least 5 in length before doing this!
edit: as #MartinR points out, you can use the with-end-index version of advance to avoid the risk of running past the end:
let index = advance(s.startIndex, 5, s.endIndex)
if index != s.endIndex { s.removeAtIndex(index) }
As ever, optionals are your friend:
// find returns index of first match,
// as an optional with nil for no match
if let idx = s.characters.index(of:",") {
// this will only be executed if non-nil,
// idx will be the unwrapped result of find
s.removeAtIndex(idx)
}

Swift 3.2
let str = "hello"
let position = 2
let subStr = str.prefix(upTo: str.index(str.startIndex, offsetBy: position)) + str.suffix(from: str.index(str.startIndex, offsetBy: (position + 1)))
print(subStr)
"helo"

var hello = "hello world!"
Let's say we want to remove the "w". (It's at the 6th index position.)
First: Create an Index for that position. (I'm making the return type Index explicit; it's not required).
let index:Index = hello.startIndex.advancedBy(6)
Second: Call removeAtIndex() and pass it our just-made index. (Notice it returns the character in question)
let choppedChar:Character = hello.removeAtIndex(index)
print(hello) // prints hello orld!
print(choppedChar) // prints w

Related

Node - Test if string contain element of array replace him by random element of same array (synonym)

I want to change each word that matches the synonym list randomly by another synonym or itself (to randomly keep this keyword).
I test if a string (input) contains one element of an array (words). If it's true, I want to randomly replace this with the element of this same list.
var input = "This is an amazing text blob where this word amazing is replaced by a random word from list_of_words. Isn't this amazing!";
words_synonym = ["amazing", "formidable", "great", "smart"];
// first condition --> true if "input" contain one element of "words_synonym"
input = input.toLowerCase();
console.log(words_synonym.some(word => input.includes(word)));
after, I want to replace the "element" that validated the condition with a random element of the same array (words_synonym).
But I can't select this element. I have just true or false
var random_word = words_synonym[Math.floor(Math.random() * (words_synonym.length))]
input = input.replace(element, random_word, 0)
thanks
The way you have it right now, you're checking if any of the synonyms match any of the words (via words_synonym.some(word => input.includes(word))). In order to do what you want, you'll need both the position of the target word and the new word, neither of which you have now. To do this, you'll want to break apart your nested loops.
The code words_synonym.some(word => input.includes(word)) is equivalent to:
let has_synonym = false;
for (word of words_synonym) { // this is a loop
if (input.includes(word)) { // this is also a loop
has_synonym = true;
break;
}
}
console.log(has_synonym);
So to fix your main issue, just replace includes with indexOf.
To handle the case of replacing all of the tokens, I would suggest keeping track of the token you have replaced outside of the loop, otherwise you end up replacing each token many times which may become very expensive. To do this, just keep track of your starting position outside of the loop and increment it with the end index of the replacement word. indexOf already takes a start argument for exactly this use case!
const input = "This is an amazing text blob where this word amazing is replaced by a random word from list_of_words. Isn't this amazing!";
const words_synonym = ["amazing", "formidable", "great", "smart"];
let output = input;
let start = 0; // index of the end of the last replaced token
for (word of words_synonym) {
let index = output.indexOf(word, start);
while (index >= 0) {
const new_word = words_synonym[Math.floor(Math.random() * (words_synonym.length))];
output = output.substr(0, index) + new_word + output.substr(index + word.length, output.length);
start = index + new_word.length + 1; // increment the start
index = output.indexOf(word, start);
}
}
console.log("input: ", input);
console.log("output: ", output);
You can use method find:
words_synonym.find(word => input.includes(word))
Which returns
The value of the first element in the array that satisfies the
provided testing function. Otherwise, undefined is returned.
from docs:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find
i have modify answer of dantiston and i have include a loop in order to change all the word match "words_synonym".
But there is a problem. The program don't check all the word of "words_synonym" but only the first with indexof.
var input = "This is an amazing text blob where this word amazing is replaced by a random word from list_of_words. Isn't this amazing!";
words_synonym = ["amazing", "formidable", "great", "smart"];
let output = input;
for (word of words_synonym) {
let index = output.indexOf(word);
if (index >= 0) {
console.log(word);
var indexes = [], i = -1;
while ((i = output.indexOf(word, i+1)) != -1){
index=output.indexOf(word, i);
var new_word = words_synonym[Math.floor(Math.random() * (words_synonym.length))];
output = output.substr(0, index) + new_word + output.substr(index + word.length, output.length);
}
}
}
console.log("input: ", input);
console.log("output: ", output);

How do I count number of words in a string in Typescript without counting extraneous spaces?

I have seen many cases where people sometimes rely on whitespaces which causes some miscalculations.
For Example, take 2 strings;
const str1: string = 'I love stackoverflow'
const str2: string = 'I love stackoverflow'
Using the numOfWhitespaces + 1 thing gives wrong number of words in case of str2. The reason is obvious that it counts 6 number of spaces.
So what should be an easy and better alternative?
The shortest would be using: str1.split(/\s+/).length
But just in case any beginner want to do it with basic loop, here it is:
let str1: string = 'I love stackoverflow'
let numberOfSpaces: number = 0
for (let index = 1; index <= str1.length; index++) {
let lastChar: string = ''
let currentChar: string = ''
currentChar = str1.charAt(index)
lastChar = str1.charAt(index - 1)
if (currentChar === " " && lastChar !== " ") {
numberOfSpaces = numberOfSpaces+ 1
}
else if (currentChar === " " && lastChar === " ") { // This is a test String.
numberOfSpaces = numberOfSpaces + 0
}
//I have not added an else statement for the case if both current char and last char are not whitespaces.
//because I felt there was no need for that and it works perfectly.
}
const finalNumberOfWords: number = numberOfSpaces + 1
console.log(`Number of words final are = ${finalNumberOfWords}`)
So this might look similar to the counting whitespaces method, yes it is but this one doesn't count the extraneous spaces [space followed by a space].
A for loop runs throughout the length of the string. It compares the character at current position of str1[index]and its previous index. If both are whitespaces, it won't count but if previous character was non-null and current is blank, it increments the counter by one.
And finally we add 1 to the counter to display number of words.
Here's a screenshot:
An alternative solution would be to use a regex:
const str2: string = 'I love stackoverflow'
console.log(str2.split(/\s+/).length);
This will ensure that multiple spaces will be splitted.
Test:
console.log('I love stackoverflow'.split(/\s+/).length);
console.log('Ilovestackoverflow'.split(/\s+/).length);

Reverse every other word in string, keep punctuation Swift

So I got stuck on a coding challenge that I almost knew the answer too. And I think I have to use the subString call in Swift 4 to get it 100%. I want to reverse every OTHER word in a string, but ignore or keep the punctuation in its original place( index ).
var sample = "lets start. And not worry about proper sentences."
func reverseString(inputString: String) -> String {
let oldSentence = sample.components(separatedBy: " ")
var newSentence = ""
for index in 0...oldSentence.count - 1 {
let word = oldSentence[index]
if newSentence != "" {
newSentence += " "
}
if index % 2 == 1 {
let reverseWord = String(word.reversed())
newSentence += reverseWord
} else {
newSentence += word
}
}
return newSentence
}
reverseString(inputString: sample)
And this would be the expected output.
"lets trats. And ton worry tuoba proper secnetnes."
Notice the punctuation is not reversed.
You shouldn't use components(separatedBy: ) to split a string in words. See this article for the reason. Use enumerateSubstrings and pass in the appropriate option:
func reverseString(inputString: String) -> String {
var index = 1
var newSentence = inputString
inputString.enumerateSubstrings(in: inputString.startIndex..., options: .byWords) { substr, range, _, stop in
guard let substr = substr else { return }
if index % 2 == 0 {
newSentence = newSentence.replacingCharacters(in: range, with: String(substr.reversed()))
}
index += 1
}
return newSentence
}
print(reverseString(inputString: "lets start. And not worry about proper sentences."))
// lets trats. And ton worry tuoba proper secnetnes.
print(reverseString(inputString: "I think, therefore I'm"))
// I kniht, therefore m'I

Swift String.removeRange cannot compile

I don't understand what to do with the issue reported by the compiler. I tried to create a Range, but it says Index is not known:
//let range = matches.first!.range.location
let range = Range(
start:matches.first!.range.location,
end: matches.first!.range.location+matches.first!.range.length
)
id = text[range]
var t = text
t.removeRange(range)
return t
Compiler says: Cannot invoke 'removeRange' with an argument list of type '(Range)' on t.removeRange(range).
I'm pretty sure it's evident, but I lost a great deal of time on such a small issue… any help highly appreciated!
As your error says that:
Cannot invoke 'removeRange' with an argument list of type '(Range)'
Means there is a problem with your range instance type and removeRange function will only accept an argument with type Range<String.Index> and its syntax is :
/// Remove the indicated `subRange` of characters
///
/// Invalidates all indices with respect to `self`.
///
/// Complexity: O(\ `count(self)`\ ).
mutating func removeRange(subRange: Range<String.Index>)
And here is working example with removeRange:
var welcome = "hello there"
let range = advance(welcome.endIndex, -6)..<welcome.endIndex
welcome.removeRange(range)
println(welcome) //hello
Hope this will help.
Swift 2.2 example of removing first 4 characters:
let range = text.startIndex..<text.startIndex.advancedBy(4)
text.removeRange(range)
That first line feels verbose. I hope newer Swift versions improve upon it.
Here is the working equivalent snippet:
static func unitTest() {
let text = "a👿bbbbb🇩🇪c"
let tag = Tag(id: "🇩🇪")
tag.regex = "👿b+"
print ("Unit test tag.foundIn(\(text)) ? = \(tag.foundIn(text))")
}
func foundIn(text: String) -> (id:String, remainingText:String)? {
// if a regex is provided, use it to capture, and keep the capture as a tag ID
if let regex = regex {
let r = Regex(regex) // text =~ regex
let matches = r.matches(text)
if matches.count >= 1 {
let first = matches.first!.range
let start = advance(text.startIndex, first.location)
let end = advance(start, first.length-1)
let range = Range(start: start, end: end)
id = text[range]
var t = text
t.removeRange(range)
return (id, t)
}
return nil
}
else if let range = text.rangeOfString(id) {
var t = text
t.removeRange(range)
return (id, t)
}
else {
return nil
}
}
The unit test returns :
Unit test tag.foundIn(a👿bbbbb🇩🇪c) ? = Optional(("👿bbbbb", "a🇩🇪c"))

Swift - Search in string and sum the numbers

Hey guys I have string "69 - 13" How to detect "-" in the string and how to sum the numbers in the string 69+13=82 ?
There are various method to do that (componentsSeparatedByString, NSScanner, ...).
Here is one using only Swift library functions:
let str = "69 - 13"
// split string into components:
let comps = split(str, { $0 == "-" || $0 == " " }, maxSplit: Int.max, allowEmptySlices: false)
// convert strings to numbers (use zero if the conversion fails):
let nums = map(comps) { $0.toInt() ?? 0 }
// compute the sum:
let sum = reduce(nums, 0) { $0 + $1 }
println(sum)
Here is an updated implementation in Swift 4 that relies on higher order functions to perform the operation:
let string = "69+13"
let number = string.components(separatedBy: CharacterSet.decimalDigits.inverted)
.compactMap({ Int($0) })
.reduce(0, +)
print(number) // 82
The components(separatedBy: CharacterSet.decimalDigits.inverted) removes all non-digit values and creates an array for each group of values (in this case 69 and 13)
Int($0) converts your string value into an Int
compactMap gets rid of any nil values, ensuring that only valid values are left
reduce then sums up the values that remain in your array

Resources