Kotlin: Operator '!=' cannot be applied to 'String?' and 'Char.Companion' - kotlin

In this Hangman game how can I give the condition to check if input !=Char? It says that Kotlin: Operator '!=' cannot be applied to 'String?' and 'Char.Companion'
How can I solve this issue?
while (letters != correctGuesses) {
printExploredWord(word, correctGuesses)
println("\n#Wrong guesses: $fails\n\n")
print("Guess letter:")
val input = readLine()
if (input == null) {
continue
} else if (input.length != 1) {
println("Please enter one letter")
continue
} else if (input != Char) {
println("Please enter a character")
}
if (word.toLowerCase().contains(input.toLowerCase())) {
correctGuesses.add(input[0].toLowerCase())
} else {
++fails
}

Sounds from your comments that what you want to check is if the input String? has a single alphabetic character. You need to be precise with your terminology. Numbers and punctuation are also made up of characters. Char is a class representing any element of a String, so it doesn't make sense to be asking if something in a String is a Char because the answer is true no matter what.
The question you need to be asking is whether the first character in the given String is a letter. There's a function for that: Char.isLetter(). And since we're checking the content of the first character of the String, we need to get its value with input[0] because it doesn't make sense to ask if a whole String is a letter character. A String is never a Char because these are different classes. So in your case you would use:
if (input == null) {
continue
} else if (input.length != 1) {
println("Please enter one letter")
continue
} else if (!input[0].isLetter()) {
println("Please enter a character")
continue
}
But again, the terminology is wrong here. You should be reminding the user to enter a letter, not a character.

Your input variable is a type String?, so there's no reason to check if it's a char or not. To check for instanceof in Kotlin you use the "is" operator. So to compare if your input is a Char you can do,
else if(!(input is Char)) {
//This is unnecessary though since you're already checking if the length of the input isn't 1
}

Related

How do I take input and make sure it's a valid double number? [duplicate]

This question already has answers here:
Kotlin - How to check double in if condition
(2 answers)
Closed 1 year ago.
My attempt so far:
var oneNum: Double
print("The first number: ");
oneNum = read.nextDouble()
If user enters anything other than numbers and a one dot the program will crash. I tried searching in google but I didn't find anything useful.
I tried to do it the long hard way by taking the input as string in readLine() and checking for anything other than numbers and then checking if there's more than one fraction dot(.) and if both conditions are true, I continue to convert the string to numbers and got stuck. This seems too complicated.
Can be done in multiple ways, but the simplest form that I can think of would be this:
println("The first number: ");
val ourDouble = readLine()?.toDoubleOrNull() ?: error("You need to enter a double")
The readLine() will get the next thing you type in the console. It can be null if you give the input is a "end of file" character.
Thus we do .? which means proceed if this is not null.
The toDoubleOrNull() will attempt to transform the "String" input into a Double, if it fails, it will return null.
The elvis operator ?: will only process what is on the right of it, if the left side is null. So it will only print the error if the readLine() is null, or if the toDoubleOrNull() is null.
Note: error("message") is the same as doing throw Exeption("message").
Read the question again, since you want to keep the user in a purgatory until they input a double, you can create a function like this:
fun fetchDoubleFromUser(): Double {
println("The first number:");
return readLine()?.toDoubleOrNull()
?: run {
println("You need to enter a double")
fetchDoubleFromUser()
}
}
or a simple while
fun fetchDoubleFromUser(): Double {
println("The first number:");
var ourNumber: Double? = null
while (ourNumber == null) {
ourNumber = readLine()?.toDoubleOrNull()
ourNumber ?: println("You need to enter a double")
}
return ourNumber
}

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

Kotlin: check if string is numeric

Is there a simple way to check if user's input is numeric? Using regexes and exceptions seems too complicated here.
fun main {
val scan = Scanner(System.`in`)
val input = scanner.nextLine()
if (!input.isNumeric) {
println("You should enter a number!")
}
}
The method mentioned above will work for a number <= approximately 4*10^18 essentially max limit of Double.
Instead of doing that since String itself is a CharSequence, you can check if all the character belong to a specific range.
val integerChars = '0'..'9'
fun isNumber(input: String): Boolean {
var dotOccurred = 0
return input.all { it in integerChars || it == '.' && dotOccurred++ < 1 }
}
fun isInteger(input: String) = input.all { it in integerChars }
fun main() {
val input = readLine()!!
println("isNumber: ${isNumber(input)}")
println("isInteger: ${isInteger(input)}")
}
Examples:
100234
isNumber: true
isInteger: true
235.22
isNumber: true
isInteger: false
102948012120948129049012849102841209849018
isNumber: true
isInteger: true
a
isNumber: false
isInteger: false
Its efficient as well, there's no memory allocations and returns as soon as any non-satisfying condition is found.
You can also include check for negative numbers by just changing the logic if hyphen is first letter you can apply the condition for subSequence(1, length) skipping the first character.
joining all the useful comments and putting it in a input stream context, you can use this for example:
fun readLn() = readLine()!!
fun readNumericOnly() {
println("Enter a number")
readLn().toDoubleOrNull()?.let { userInputAsDouble ->
println("user input as a Double $userInputAsDouble")
println("user input as an Int ${userInputAsDouble.toInt()}")
} ?: print("Not a number")
}
readNumericOnly()
for input: 10
user input as a Double 10.0
user input as an Int 10
for input: 0.1
user input as a Double 0.1
user input as an Int 0
for input: "word"
Not a number
Simply use : text.isDigitsOnly() in kotlin.
Well all the answers here are best suited for their own scenarios:
But not all string are numeric digits it can have (-) and (.) decimal pointers.
So to accomplish this I made a cocktail of all the answers suggested below and from other posts as well which - looks like below :
fun isPosOrNegNumber(s: String?) : Boolean {
return if (s.isNullOrEmpty()) false
else{
if(s.first()=='-' && s.filter { it == '.' }.count() <= 1) {
s.removeRange(0,1).replace(".","").all{Character.isDigit(it)}
}
else s.all {Character.isDigit(it)}
}
}
Above code does a good job for its purpose.
But then it struck me kotlin does an even better job with matching a regex and voila the solution became simple and elegant as below :
fun isPosOrNegNumber(s: String?) : Boolean {
val regex = """^(-)?[0-9]{0,}((\.){1}[0-9]{1,}){0,1}$""".toRegex()
return if (s.isNullOrEmpty()) false
else regex.matches(s)
}
This sample regex is only for US number formats but if you want to use EU number formats then just replace '.' with ','
Bdw. if the numbers contain commas then just replace it while sending to this method or better form a regex pattern with commas in it.
Another way to check if the given string is numeric( to check for both negative and positive values ) or not:
val intChars = '0'..'9'
fun isNumeric(input: String) = input
.removePrefix("-")
.all { it in '0'..'9' }
A simple answer without any custom functions is to utilise toDoubleOrNull function. If it returns null, the string is not numeric.
val string = "-12345.666"
if (string.toDoubleOrNull()!=null) // string is numeric
{
//do something
}
If you know the input only contains integers you can also use toIntOrNull likewise

How to properly iterate over arrays in kotlin

I am currently learning kotlin and therefore following the kotlin track on exercism. The following exercise required me to calculate the Hamming difference between two Strings (so basically just counting the number of differences).
I got to the solution with the following code:
object Hamming {
fun compute(dnaOne: String, dnaTwo: String): Int {
if (dnaOne.length != dnaTwo.length) throw IllegalArgumentException("left and right strands must be of equal length.")
var counter = 0
for ((index, letter) in dnaOne.toCharArray().withIndex()) {
if (letter != dnaTwo.toCharArray()[index]) {
counter++
}
}
return counter
}
}
however, in the beginning I tried to do dnaOne.split("").withIndex() instead of dnaOne.toCharArray().withIndex() which did not work, it would literally stop after the first iteration and the following example
Hamming.compute("GGACGGATTCTG", "AGGACGGATTCT") would return 1 instead of the correct integer 9 (which only gets returned when using toCharArray)
I would appreciate any explanation
I was able to simplify this by using the built-in CharSequence.zip function because StringimplementsCharSequence` in Kotlin.
According to the documentation for zip:
Returns a list of pairs built from the characters of this and the [other] char sequences with the same index
The returned list has length of the shortest char sequence.
Which means we will get a List<Pair<Char,Char>> back (a list of pairs of letters in the same positions). Now that we have this, we can use Iterable.count to determine how many of them are different.
I implemented this as an extension function on String rather than in an object:
fun String.hamming(other: String): Int =
if(this.length != other.length) {
throw IllegalArgumentException("String lengths must match")
} else {
this.zip(other).count { it.first != it.second }
}
This also becomes a single expression now.
And to call this:
val ham = "GGACGGATTCTG".hamming("AGGACGGATTCT")
println("Hamming distance: $ham")

Checking if string is empty in Kotlin

In Java, we've always been reminded to use myString.isEmpty() to check whether a String is empty. In Kotlin however, I find that you can use either myString == "" or myString.isEmpty() or even myString.isBlank().
Are there any guidelines/recommendations on this? Or is it simply "anything that rocks your boat"?
Thanks in advance for feeding my curiosity. :D
Don't use myString == "", in java this would be myString.equals("") which also isn't recommended.
isBlank is not the same as isEmpty and it really depends on your use-case.
isBlank checks that a char sequence has a 0 length or that all indices are white space. isEmpty only checks that the char sequence length is 0.
/**
* Returns `true` if this string is empty or consists solely of whitespace characters.
*/
public fun CharSequence.isBlank(): Boolean = length == 0 || indices.all { this[it].isWhitespace() }
/**
* Returns `true` if this char sequence is empty (contains no characters).
*/
#kotlin.internal.InlineOnly
public inline fun CharSequence.isEmpty(): Boolean = length == 0
For String? (nullable String) datatype, I use .isNullOrBlank()
For String, I use .isBlank()
Why? Because most of the time, I do not want to allow Strings with whitespace (and .isBlank() checks whitespace as well as empty String). If you don't care about whitespace, use .isNullorEmpty() and .isEmpty() for String? and String, respectively.
Use isEmpty when you want to test that a String is exactly equal to the empty string "".
Use isBlank when you want to test that a String is empty or only consists of whitespace ("", " ").
Avoid using == "".
There are two methods available in Kotlin.
isNullOrBlank()
isNullOrEmpty()
And the difference is:
data = " " // this is a text with blank space
println(data.isNullOrBlank()?.toString()) //true
println(data.isNullOrEmpty()?.toString()) //false
You can use isNullOrBlank() to check is a string is null or empty. This method considers spaces only strings to be empty.
Here is a usage example:
val s: String? = null
println(s.isNullOrBlank())
val s1: String? = ""
println(s1.isNullOrBlank())
val s2: String? = " "
println(s2.isNullOrBlank())
val s3: String? = " a "
println(s3.isNullOrBlank())
The output of this snippet is:
true
true
true
false
As someone mentioned in the comments, you can use ifBlank, like so:
fun getSomeValue(): String {
// ...
val foo = someCall()
return foo.ifBlank { "some-default" }
}
Documentation: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/if-blank.html