How do I replace letters with numbers using the replace function in kotlin inside a lambda expression - kotlin

mood = "leet"
modifier = { message ->
val regex = """(L|e|t)""".toRegex()
//Clueless about what to do after this
}
THIS IS WHAT I CAME UP WITH SO FAR, THE QUESTION IN THE BOOK BIG NERD RANCH KOTLIN EDITION 2 SAYS "leet (or 1337): The narrator will speak in leetspeak, replacing letters with numbers and symbols that look similar. For example, ‘L’ becomes ‘1’; ‘E’ becomes ‘3’; ‘T’ becomes ‘7’. (Hint: Take a look at String’s replace function. There is a version that accepts a lambda as the second parameter.)"

This is the function they're telling you to look at, specifically this one:
inline fun CharSequence.replace(
regex: Regex,
noinline transform: (MatchResult) -> CharSequence
): String
Returns a new string obtained by replacing each substring of this char sequence that matches the given regular expression with the result of the given function transform that takes MatchResult and returns a string to be used as a replacement for that match.
So the lambda you provide is a function that takes a MatchResult
and does something with it, and returns a CharSequence (which can be a one-character long String). The replace function calls that lambda for every match that regex makes.
You get the general idea of what you're supposed to do? You have two parts here - the thing that identifies parts of the input string to process, and the thing that takes those matches and changes them into something else. The result is the original string with those changes made. So you need to come up with a regex and a transform that work together.
Nobody (probably) is going to tell you the answer because the point is figuring it out for yourself, but if you have any questions about things like regexes people will be happy to help you out! And speaking of, this site is extremely useful (I just used it myself to check I knew what I was doing): https://regex101.com/

Here is the implementation as pointed by #cactustictacs :
5 -> {
mood = "leet"
val regex: Regex = """[LET]""".toRegex()
modifier = { message ->
message.uppercase().replace(regex) { m ->
when (m.value) {
"L" -> "1"
"E" -> "3"
"T" -> "7"
else -> ""
}
}
}
}
and here is the another method almost same but with minor change using regex.replace()
5 -> {
mood = "leet"
val regex: Regex = """[LET]""".toRegex()
modifier = { message ->
regex.replace(message.uppercase()){m ->
when (m.value) {
"L" -> "1"
"E" -> "3"
"T" -> "7"
else -> ""
}
}
}
}
You can use it in place of m to make it slightly more concise.

Related

Counting how many times specific character appears in string - Kotlin

How one may count how many times specific character appears in string in Kotlin?
From looking at https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/ there is nothing built-in and one needs to write loop every time (or may own extension function), but maybe I missed a better way to achieve this?
Easy with filter {} function
val str = "123 123 333"
val countOfSymbol = str
.filter { it == '3' } // 3 is your specific character
.length
println(countOfSymbol) // output 5
Another approach
val countOfSymbol = str.count { it == '3'} // 3 is your specific character
println(countOfSymbol) // output 5
From the point of view of saving computer resources, the count decision(second approach) is more correct.

Call a member function in a case of a when statement?

For example, Char has a member function isLetter(). Is there any way to call it in a case? The code below does not work.
var ch:Char = null;
when(ch)
{
'*' -> print("You typed an asterisk.");
isLetter() -> print("You typed a letter.");
else -> print("You typed something.");
}
The uses of the parameter to when are quite restrictive: equality, order with < &c, inclusion with in, type checking with is, and that's about it.  So for anything more complex, it's usually easier not to specify a parameter.  In this case, the following isn't much less concise or clear:
when {
ch == '*' -> print("You typed an asterisk.")
ch.isLetter() -> print("You typed a letter.")
else -> print("You typed something.")
}
Some points worth noting:
Semicolons are not needed in Kotlin (except for a few rare ambiguous cases such as putting multiple statements on a line — which is rarely a good idea).
print() does not add a trailing newline, which can cause problems; println() is more common.
var ch: Char = null won't compile, because the type Char is not nullable.  Either give a non-null default value, or make it nullable by specifying the type as Char?.  However, in the latter case, you won't be able to call ch.isLetter(), because that would risk a NullPointerException.  So you'd either need to add a null case before that, or handle the null in that check, either with ch != null && ch.isLetter(), or ch?.isLetter() == true — both of which are ugly.
There is, but there's also the possibility of it not being applicable in your situation.
when can be used without an argument, like this:
fun main() {
val ch: Char = 'd'
when {
ch.isLetter() -> println("It's a letter")
ch.isDigit() -> println("It's a number")
else -> println("It's neither a letter, nor a number")
}
}
But if you make ch nullable like var ch: Char? = null, you won't be able to call member functions in that when clause.
You can check whether ch is in a specific CharCategory. For isLetter() those are the following five:
when(ch)
{
'*' -> print("You typed an asterisk.")
in CharCategory.UPPERCASE_LETTER,
in CharCategory.LOWERCASE_LETTER,
in CharCategory.TITLECASE_LETTER,
in CharCategory.MODIFIER_LETTER,
in CharCategory.OTHER_LETTER -> print("You typed a letter.")
else -> print("You typed something.")
}
first in your code var ch:Char = null
it must be Char?
the solution is simple don't put argument:
var ch:Char = 'c'
when {
ch == '*' -> println("*")
ch.isLetter() -> println("letter")
ch.isDigit() -> println("digit")
}
hope my answer helped you

Distinguish functions with lambda argument by lambda's return type?

I have a function timeout(...) (extension function that returns this) which accepts an argument that is either String, Date or Long. What I am trying to do is to make it accept any lambda that also returns one of these three types.
Kotlin finds the below functions ambiguous and can't decide which one to call when I type, for example, timeout { "something" }.
#JvmName("timeoutString")
fun <CR: CachableResponse> CR.timeout(timeLambda: CR.()->String): CR = timeout(timeLambda())
#JvmName("timeoutLong")
fun <CR: CachableResponse> CR.timeout(timeLambda: CR.()->Long): CR = timeout(timeLambda())
#JvmName("timeoutDate")
fun <CR: CachableResponse> CR.timeout(timeLambda: CR.()->Date): CR = timeout(timeLambda())
The error I'm getting is Cannot choose among the following candidates without completing type inference.
Of course one way to work around this, is to have one function instead of three like this:
fun <CR: CachableResponse, Type> CR.timeout(timeLambda: CR.()->Type): CR =
timeLambda().let { when (it) {
is String -> timeout(it)
is Date -> timeout(it)
is Long -> timeout(it)
else -> this
} }
In this case, though, the developer won't have any clue what its lambda will have to return without reading the description or checking the source code.
Is there any more elegant solution?
Actually, you solution is rather elegant.
I would only suggest to inline CR generic parameter and capture when subject in a variable:
fun <Type> CachableResponse.timeout(timeLambda: CachableResponse.() -> Type) =
when (val it = timeLambda()) {
is String -> timeout(it)
is Date -> timeout(it)
is Long -> timeout(it)
else -> this
}
In this case, though, the developer won't have any clue what its lambda will have to return without reading the description or checking the source code.
IDE comes to the rescue:

How to print ClosedRange in Kotlin

I'm learning Kotlin , and I'm trying to undetstand Ranges
I created a range of String as follows
val alpha = "A".."Z"
I want to print this for that I wrote
for (item in alpha) println(item)
But it gives the error
Error:(13, 18) Kotlin: For-loop range must have an 'iterator()' method
Can anyone help, how to print this range?
Well you can't do it with Strings by default, since there's no iterator() for ClosedRange<String>, but Chars will work directly:
val r = 'A'..'Z'
r.forEach(::println)
It will be of type CharRange and provide the needed iterator().
To make your very special example work with Strings, you could define your own extension function and delegate to a Iterator<Char>:
operator fun ClosedRange<String>.iterator(): Iterator<String> {
val charIt = (start.toCharArray().first()..endInclusive.toCharArray().first()).iterator()
return object : Iterator<String> {
override fun hasNext() = charIt.hasNext()
override fun next(): String = charIt.nextChar().toString()
}
}
Now it works as you wished. But be aware that this does not make sense for most use cases with ranges of String.
val alpha = "A".."Z"
This is a plain range, which means it's an abstract representation of a contiguous subset within a total order. The only operation such an entity supports is answering the question "is this element within this range?", and it will be based purely on the contract of Comparable<T>.
In your case, consider a string like "THREAD". Does it belong to your range? It sorts higher than "A" but lower than "Z", so it does belong to it. But you probably didn't intend to iterate over it, or the infinity of all other strings belonging to your range.
What you considered as a given is actually a special case: iterable ranges. They are defined only on the three types representing integral types: IntRange, LongRange and CharRange. These are the types where the subset belonging to the range can actually be enumerated and iterated over.
I Loved The answers of #s1m0nw1 and #Marko Topolnik.
You can't really iterate over a ClosedRange<String>.
The literal may mislead us to think it's a ClosedRange<Char>
var range = "A".."C" // misleading literal
What you CAN do:
Just a small addition: is to map the characters to Strings
val r = ('A'..'Z').map { it.toString() }//.forEach(::println)
for (letter in r){
}
How to print this range?
I think the only way to print this range is
println(alpha)
And you'll get
A..Z
This is how to "print" this range.
You're trying to travel through a non-iterable range, this is invalid.
Like, you cannot for (i in File("a.txt")..File("Main.java")) println(i).
Can You Try This May Help You, I think you actually want 'A'..'Z' not "A".."Z"
var A = 'A'..'Z'
for(value in A){
println("$value")
}

What does the arrow ("->") operator do in Kotlin?

Probably a little bit broad question, but the official documentation doesn't even mentioning the arrow operator (or language construct, I don't know which phrase is more accurate) as an independent entity.
The most obvious use is the when conditional statement, where it is used to assign an expression to a specific condition:
val greet = when(args[0]) {
"Appul" -> "howdy!"
"Orang" -> "wazzup?"
"Banan" -> "bonjur!"
else -> "hi!"
}
println(args[0] +" greets you: \""+ greet +"\"")
What are the other uses, and what are they do?
Is there a general meaning of the arrow operator in Kotlin?
The -> is part of Kotlin's syntax (similar to Java's lambda expressions syntax) and can be used in 3 contexts:
when expressions where it separates "matching/condition" part from "result/execution" block
val greet = when(args[0]) {
"Apple", "Orange" -> "fruit"
is Number -> "How many?"
else -> "hi!"
}
lambda expressions where it separates parameters from function body
val lambda = { a:String -> "hi!" }
items.filter { element -> element == "search" }
function types where it separates parameters types from result type e.g. comparator
fun <T> sort(comparator:(T,T) -> Int){
}
Details about Kotlin grammar are in the documentation in particular:
functionType
functionLiteral
whenEntry
The -> is a separator. It is special symbol used to separate code with different purposes. It can be used to:
Separate the parameters and body of a lambda expression
val sum = { x: Int, y: Int -> x + y }
Separate the parameters and return type declaration in a function type
(R, T) -> R
Separate the condition and body of a when expression branch
when (x) {
0, 1 -> print("x == 0 or x == 1")
else -> print("otherwise")
}
Here it is in the documentation.
From the Kotlin docs:
->
separates the parameters and body of a lambda expression
separates the parameters and return type declaration in a function
type
separates the condition and body of a when expression branch