I have a fun that replaces comma with empty string. Then converts it to double. User can input only numbers and commas. After replace I want to take this string only if its not empty for conversion purposes. But although its empty takeIf{} doesnt seem to see it this way. When I enter only "," as first char in a string, the conversion fails throwing:
java.lang.NumberFormatException: empty String
Scenario when entering , as first char.
replace(",", "")
.takeIf {
println(it) //prints nothing
println(it.length) //prints 0
if (isNotEmpty()) { // docs says that it checks if length > 0, which is not, so string is empty
println("not empty") // still prints not empty
} else {
println("empty")
}
isNotEmpty()
}?.toDouble()) // runs toDouble on empty string
Logs:
System.out: 0
System.out: not empty
Note that replace returns the adapted String, but does not alter the underlying string... So when you call isNotEmpty() you check for the initial/receiver String (which was ","), but when you print the content or the length, you take the result of the replacement (it).
So if you use it consequently, it will work as you expect.
Note also that there exists toDoubleOrNull() which just returns null if no double can be extracted from the String, e.g:
replace(",", "").toDoubleOrNull() // if it is not parseable, we get null
So you can spare even more characters and conditions in your code.
Related
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
}
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
}
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
I need some help here, I am currently making a game, but I got stuck somewhere. So, what I want is, if a Labels text is higher then the other labels text, then something will happen, I typed If Label26.Text > Label24.Text Then Label33.Visible = True which seems not to work, please, I need some help here, thanks. And yes, the labels text is NUMBERS.
The Text property of a label is a string. As far as computers go, you can't do math (using comparison operators like > will not return the result you are expecting) with strings because they are just a sequence of characters.
Even if the string only contains a number, the computer still sees it as a sequence of characters and not a number ("5" is a string literal with the character 5 in it, while 5 is an integer that can be used in a mathematic expression).
As some of the other commenters mentioned, you need to cast the Text property to an Integer or Double (or some other numeric data type). To do so, you'd want to use Int32.Parse to change the strings to integers.
If Int32.Parse(Label26.Text) > Int32.Parse(Label24.Text) Then Label33.Visible = True
You can use the int.tryParse to check if the content of the variable is a number or not. The output of the TryParse is a boolean, see the example below:
int num1 = 0;
bool num1_ = false;
num1_ = int.TryParse(txt1.Text.ToString(), out num1);
if (num1_)
{
// Is a number/integer
//Do something
}
else
{
//Is a string
//Do something else
}
Here's what I'm trying to do. A user can type in a search string, which can include '*' or '?' wildcard characters. I'm finding this works with regular strings but not with ones including numeric characters.
e.g:
414D512052524D2E535441524B2E4E45298B8751202AE908
1208
if I look for a section of that hex string, it returns false. If I look for "120" or "208" in the "1208" string it fails.
Right now, my regular expression pattern ends up looking like this when a user enters, say "w?f": '\bw.?f\b'
I'm (obviously) not well-versed in regular expressions at the moment, but would appreciate any pointers someone may have to handle numeric characters in the way I need to - thanks!
Code in question:
/**
*
* #param searchString
* #param strToBeSearched
* #return
*/
public boolean findString(String searchString, String strToBeSearched) {
Pattern pattern = Pattern.compile(wildcardToRegex(searchString));
return pattern.matcher(strToBeSearched).find();
}
private String wildcardToRegex(String wildcard){
StringBuffer s = new StringBuffer(wildcard.length());
s.append("\\b");
for (int i = 0, is = wildcard.length(); i < is; i++) {
char c = wildcard.charAt(i);
switch(c) {
case '*':
s.append(".*");
break;
case '?':
s.append(".?");
break;
default:
s.append(c);
break;
}
}
s.append("\\b");
return(s.toString());
}
Let's assume your string to search in is
1208
The search "term" the user enters is
120
The pattern then is
\b120\b
The \b (word boundary) meta-character matches beginning and end of "words".
In our example, this can't work because 120 != 1208
The pattern has to be
\b.*120.*\b
where .* means match a variable number of characters (including null).
Solution:
either add the .*s to your wildcardToRegex(...) method to make this functionality work out-of-the-box,
or tell your users to search for *120*, because your * wildcard character does exactly the same.
This is, in fact, my preference because the user can then define whether to search for entries starting with something (search for something*), including something (*something*), ending with something (*something), or exactly something (something).