How to replace all occurrences of a sub string in kotlin - kotlin

How to replace a part of a string with something else in Kotlin?
For example, changing "good morning" to "good night" by replacing "morning" with "night"

fun main(args: Array<String>) {
var a = 1
// simple name in template:
val s1 = "a is $a"
a = 2
// arbitrary expression in template:
val s2 = "${s1.replace("is", "was")}, but now is $a"
println(s2)
}
OUPUT: a was 1, but now is 2

"Good Morning".replace("Morning", "Night")
It's always useful to search for functions in the Kotlin standard library API reference. In this case, you find the replace function in Kotlin.text:
/**
* Returns a new string with all occurrences of [oldChar] replaced with [newChar].
*/
public fun String.replace(oldChar: Char, newChar: Char, ignoreCase: Boolean = false): String {
if (!ignoreCase)
return (this as java.lang.String).replace(oldChar, newChar)
else
return splitToSequence(oldChar, ignoreCase ignoreCase).joinToString(separator = newChar.toString())
}

Related

Count the number of punctuation symbols in a string Kotlin

I have a question how can I count the number of punctuation symbols in a string.
Here is my code snippet
fun punctuationCount(stringValue: Editable): Int {
val trimmedStr = stringValue.trim()
return if (trimmedStr.isEmpty()) {
0
} else {
return trimmedStr.split("[a-zA-Z&&[ \t]]".toRegex()).size
}
}
You can make use of the built-in count function on CharSequence to count the occurrence of arbitrary characters.
val testString = "Some string containing punctuation, like !, #, #, etc."
val punctuationChars = setOf('!', '#', '#', '$', '%', '.')
val occurrences = testString.count { char -> char in punctuationChars }
println("I've counted $occurrences occurrences!")
If you need this functionality more often, you might want to extract it into an extension function, e.g.
fun CharSequence.countCharacters(searchedCharacters: Set<Char>): Int =
this.count { char -> char in searchedCharacters }
val punctuationChars = setOf('!', '#', '#', '$', '%', '.')
fun CharSequence.countPunctuationCharacters(): Int =
this.countCharacters(punctuationChars)
Then you can do
val occurrences = testString.countPunctuationCharacters()
Thanks to #CryptoFool for the example string.
Here's a version of your function that demonstrates what you're asking for:
fun punctuationCount(stringValue: String): Long {
val trimmedStr = stringValue.trim()
return if (trimmedStr.isEmpty()) {
return 0
} else {
val exp = Pattern.compile("\\p{Punct}")
val matcher = exp.matcher(trimmedStr)
return matcher.results().count()
}
}
If you don't like the Pattern library's definition of what constitutes punctuation, you can replace the line that computes the Pattern object with something like this that lets you define punctuation characters explicitly:
val exp = Pattern.compile("[!##\$%.]")
Another variation - the Unicode standard defines a bunch of categories (see 4.4) that a character can fall into, and those are present in Kotlin, so you could make use of those if you like
import kotlin.text.CharCategory.*
val punctuation = setOf(
DASH_PUNCTUATION, START_PUNCTUATION, END_PUNCTUATION,
CONNECTOR_PUNCTUATION, OTHER_PUNCTUATION
)
val testString = "Some string containing punctuation, like !, #, #, etc."
fun main() {
testString.count { it.category in punctuation }.run(::println)
}
>>> 8
You'd have to decide if those cover your needs, or which ones to include and exclude (and symbols are a different category class). Just throwing it out there as an option / something to know about!

Mapping array elements using a function in Kotlin

New to Kotlin from Python. In Python, I can simply use the code below to pass each element of a List to a multiline function and return an iterator of the result.
countArr = list(map(countReps, arr))
In Kotlin, I found that I had to do the following. Am I missing something?
fun LetterCountI(str: String): String {
val arr = str.split(" ")
var transform:(String) -> Int = {countReps(it)}
val countArr = arr.map(transform)
val mxIndex:Int
var ans:String
if (countArr.max()!=1){
mxIndex = countArr.indexOf(countArr.max())
ans = arr[mxIndex]
} else {
ans = "-1"
}
return ans;
}
fun countReps(str: String): Int {
var m = mutableMapOf<Char, Int>()
var v:Int
for (c in str){
if (c in m.keys){
v = m[c]?:0
m.put(c,v+1)
} else {
m.put(c,1)
}
}
return m.values.max() ?: 0
}```
I'm having a bit of a hard time understanding your code, but one thing I can tell you is that you can replace
var transform:(String) -> Int = {countReps(it)}
val countArr = arr.map(transform)
with
val countArr = arr.map(::countReps)
In addition to the line you ask about, just about all of that code could be rewritten more concisely and idiomatically in Kotlin. For example:
fun String.wordWithMostRepeatedLetters()
= split(" ")
.associateWith{ it.maxRepeatedLetters() }
.filter{ it.value > 1 }
.maxByOrNull{ it.value }?.key ?: "-1"
fun String.maxRepeatedLetters()
= groupBy{ it }.map{ it.value.size }.maxOrNull() ?: 0
I've renamed the functions to try to explain what they give; replaced the countArr list with a map from each word to its count, so that you don't need to re-scan it to find the word resulting; and changed both functions to take a String receiver instead of a parameter. Then, because each variable was only used once, I removed them and made it all in-line, using an expression body for each function.
Some of those things don't always improve clarity, of course, especially for long functions — but I hope it demonstrates how concise Kotlin can be. (Hopefully without sacrificing maintainability. Which version would be easier to read? Which would be more likely to harbour subtle bugs?)
It's still not clear what the hard-coded "-1" return value indicates, though… If no word has any repeated letters, a null return would be more idiomatic. (Or it would be simpler just to return the first word, removing the filter() call, and returning null only if the string is blank.)

kotlin string helpers to find index in a string where any element of another string matches first/last etc

C++ has string functions like find_first_of(), find_first_not_of(), find_last_of(),
find_last_not_of(). e.g. if I write
string s {"abcdefghi"};
s.find_last_of("eaio") returns the index of i
s.find_first_of("eaio") returns the index of a
s.find_first_not_of("eaio") returns the index of b
Does Kotlin has any equivalent.
Kotlin doesn't have these exact functions, but they are all special cases of indexOfFirst and indexOfLast:
fun CharSequence.findFirstOf(chars: CharSequence) = indexOfFirst { it in chars }
fun CharSequence.findLastOf(chars: CharSequence) = indexOfLast { it in chars }
fun CharSequence.findFirstNotOf(chars: CharSequence) = indexOfFirst { it !in chars }
fun CharSequence.findLastNotOf(chars: CharSequence) = indexOfLast { it !in chars }
These will return -1 if nothing is found.
Usage:
val s = "abcdefghi"
val chars = "aeiou"
println(s.findFirstOf(chars))
println(s.findFirstNotOf(chars))
println(s.findLastOf(chars))
println(s.findLastNotOf(chars))
Output:
0
1
8
7

how to replace duplicated string using re{n,} in Kotlin?

I want change "aaa" or "aa..." to "." using Regex(re{2,})
Below is my code
var answer = "aaa"
var re = Regex("re{2,}a") // Regex("are{2,}")
answer = re.replace(answer,".")
println(answer)
Regex("re{2,}a") and Regex("are{2,}")
Both println aaa
How can I replace duplicated string using re{n,} ??
fun main(args: Array<String>) {
var tests = arrayOf("a","aa","aaa","aaaa")
val re = Regex("a(a+)")
tests.forEach {t->
val result = re.replace(t,".")
println(result)
}
}
output:
a
.
.
.
Generic regex to replace any duplicates (not only duplicate a symbols) is (?<symbol>.)\k<symbol>+
You may define an extension function for convenient usage:
private val duplicateRegex = "(?<symbol>.)\\k<symbol>+".toRegex()
fun String.replaceDuplicatesWith(replacement: String): String = replace(duplicateRegex, replacement)
Usage:
println("a".replaceDuplicatesWith(".")) //a
println("aaa".replaceDuplicatesWith(".")) //.
println("aa...".replaceDuplicatesWith(".")) //..
If you want duplicates to be iteratively replaced (like "aa..." -> ".." -> ".") you'll need an auxilary recursive method:
tailrec fun String.iterativelyReplaceDuplicatesWith(replacement: String): String {
val result = this.replaceDuplicatesWith(replacement)
return if (result == this) result else result.iterativelyReplaceDuplicatesWith(replacement)
}
Usage:
println("a".iterativelyReplaceDuplicatesWith(".")) //a
println("aaa".iterativelyReplaceDuplicatesWith(".")) //.
println("aa...".iterativelyReplaceDuplicatesWith(".")) //.

Kotlin replace multiple words in string

How to replace many parts of a string with something else in Kotlin using .replace()
For example, we can do it only by replacing one word
fun main(args: Array<String>) {
var w_text = "welcome his name is John"
println("${w_text.replace("his","here")}")
}
and the result will be " welcome here name is John " .
finally we need the result be " welcome here name is alles "
by replacing his to here and john to alles using .replace()
You can do it using multiple consecutive calls to replace():
w_text.replace("his", "here").replace("john", "alles")
You could write an extension that overloads String::replace:
fun String.replace(vararg replacements: Pair<String, String>): String {
var result = this
replacements.forEach { (l, r) -> result = result.replace(l, r) }
return result
}
fun main(args: Array<String>) {
val sentence = "welcome his name is John"
sentence.replace("his" to "here", "John" to "alles")
}
If you have many of those replacement rules, then create a mapping of them and call the replace method in a loop:
val map = mapOf("his" to "here", "john" to "alles", ...)
val sentence = "welcome his name is John"
var result = sentence
map.forEach { t, u -> result = result.replace(t, u) }
println(result)
For the ones interested in replacing a map of values in a text:
private fun replaceText(text: String, keys: Map<String, String>): String =
val replaced = map.entries.fold(text) { acc, (key, value) -> acc.replace(key, value) }
Here is a one liner:
fun String.replace(vararg pairs: Pair<String, String>): String =
pairs.fold(this) { acc, (old, new) -> acc.replace(old, new, ignoreCase = true) }
Test:
#Test fun rep() {
val input = "welcome his name is John"
val output = input.replace("his" to "her", "john" to "alles")
println(output)
output shouldBeEqualTo "welcome her name is alles"
}
Similar to other responses but using Kotlin extension and overloading String::replace to accept a map of oldValue to newValue.
fun String.replace(mapping: Map<String, String>): String {
var str = this
mapping.forEach { str = str.replace(it.key, it.value) }
return str
}
Usage:
val mapping = mapOf("his" to "here", "John" to "alles")
"his dad is John".replace(mapping) // here dad is alles
The issue with just using replace without any regex is:
Let's say I want to replace the occurrence of "here" with "there" inside the string "Where is my bag? Your bag is here." As you can imagine the result will be "Wthere is my bag? Your bag is there." which will not be correct. The solution is to use a regex like given below.
var str = "Where is my bag? Your bag is here."
val replacements = setOf("\\bhere\\b" to "there",
"\\bjohn\\b" to "alles")
replacements.forEach {
str = str.replace(Regex(it.first), it.second)
}