Kotlin: check if string is numeric - kotlin

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

Related

can't get Kotlin to check if variable in listOf

I've tried this 10 different ways and i can't get this to work.
I want this Kotlin code to take in a string, check each character of that string against a listOf characters, and, if it is in that list, increase a counting variable by 1, so then at the end it can check if that counting variable is high enough to pass a test. this is taken straight from Sololearn: Code Coach - Password Validator. I have completed this code successfully already in Python (https://code.sololearn.com/c0fl17IMHPfC), but in trying to convert it over to Kotlin, it doesn't seem to work. The variables don't seem to register as true when compared to the elements in the listOf.
fun main() {
var password: String = readLine()!!
var numberCount: Int = 0
var numbers: List<String> = listOf("0","1","2","3","4","5","6","7","8","9")
var specialCount: Int = 0
var specialCharacters: List<String> = listOf("!","#","#","$","%","&","*")
if (password.length < 7) {
println("Weak")
} else {
for (character in password) {
println(character)
var numberCheck = numbers.contains(character)
println(numberCheck)
if (numberCheck == true) {
numberCount += 1
}
var specialCharactersCheck = specialCharacters.contains(character)
println(specialCharactersCheck)
if (specialCharactersCheck == true) {
specialCount += 1
}
}
println(numberCount)
println(specialCount)
if (numberCount < 2) {
println("Weak")
} else if (specialCount < 2) {
println("Weak")
} else {
println("Strong")
}
}
}
When I enter an input of "letssee43$#", the result of this code is:
l
false
false
e
false
false
t
false
false
s
false
false
s
false
false
e
false
false
e
false
false
4
false
false
3
false
false
$
false
false
false
false
0
0
Weak
Type inference failed. The value of the type parameter T should be mentioned in input types (argument types, receiver type or expected type). Try to specify it explicitly.
Type inference failed. The value of the type parameter T should be mentioned in input types (argument types, receiver type or expected type). Try to specify it explicitly.
Your list is a list of Strings, but for (character in password) loops over the Chars in password. So you're trying to see if one of the Strings in your list is a specific Char, which it isn't, because they're two different types - a string with a single character in it is still a String, not a Char (that's why you're getting that type error)
There are lots of ways to do it (and there's nothing wrong with your code besides the Char/String thing!), personally I'd just do this:
var numbers = "0123456789"
var specialCharacters = "!##$%&*"
val password = "letssee43$#"
val nums = password.count { it in numbers }
val specials = password.count { it in specialCharacters }
println("nums: $nums, specials: $specials")
> nums: 2, specials: 2
count is iterating over the Chars in password and counting how many of them each character string contains. A String is treated like an array of Chars, so you can check it that way. (You could also add .toList() after the string declaration if you really want your characters stored in a list - that way it'll be a List<Char> so the lookup will still work.)
Or you could do things the way you are, and explicitly write out the listOf elements - but make them Chars instead, e.g. listOf('1') (single quotes) instead of listOf("1") (double quotes).
If you do want to search a list of strings for a match, you need to provide a String, so you need to convert your Char to one, e.g. by calling toString() on it, using a literal like "$character", etc.
edit like gidds points out below, sets are way more efficient for lookups like in or contains, so toSet() is a better idea than toList() unless you really need that ordered list for some reason. If you don't care about efficiency (like if you're not doing a lot of lookups) I'd personally just leave it as a string like in the code block up there - it's nice and simple. But if you do want to be more efficient, or if you do need a collection (like if you're matching against Strings) then a Set is ideal
I will give you another way to get the same result as you by using Extensions
fun main() {
var password: String = readln()
println("Password contain numbers amount: " + password.containNumbersAmount())
println("Password contain special characters amount: "+ password.containSpecialCharactersAmount())
println("Password Status : "+ password.validationResult())
}
fun String.containNumbersAmount() = count { it.isDigit() }
fun String.containSpecialCharactersAmount(): Int {
val specialCharacters = "!##$%&*"
return count { it in specialCharacters } }
fun String.validationResult() : String {
return when {
length < 7 -> "Weak"
containNumbersAmount() < 2 -> "Weak"
containSpecialCharactersAmount() < 2 -> "Weak"
else -> "Strong"
}
}
The problem is that your Lists contain Strings, so every time you call contains on them and pass a Char, it will always be false because a Char is not a String.
Probably, the best way to fix it is to declare Iterables of Chars to check them. Lists are Iterables, but so are ranges.
val password: String = readln()
var numberCount: Int = 0
val numbers: Iterable<Char> = '0'..'9'
var specialCount: Int = 0
val specialCharacters: List<Char> = listOf('!','#','#','$','%','&','*')
And just for your learning, there's a count function that takes a lambda argument that can make this kind of task much easier:
fun main() {
val password: String = readln()
val numbers = '0'..'9'
val specialCharacters = listOf('!','#','#','$','%','&','*')
val numberCount: Int = password.count { numbers.contains(it) }
val specialCount: Int = password.count { specialCharacters.contains(it) }
val result = when {
password.length < 7 || numberCount < 2 || specialCount < 2 -> "Weak"
else -> "Strong"
}
println(result)
}

Show or hide decimals

I have a double value, if that number is like this: 123.00 I need to show it as 123 only, without decimal places, but, if the number is like 123.23 or 123.2, I need to show it with the present decimal places: 123.23 or 123.2, as the case may be.
I have tried with decimal format but I couldn't find the right pattern.
It is a better way to do this than a string conversion and operate with substrings and things like that?
DecimalFormat is what you're looking for I think:
import java.text.DecimalFormat
fun main(args : Array<String>) {
val df = DecimalFormat("0.##")
println(df.format(123.0))
println(df.format(123.3))
println(df.format(123.32))
println(df.format(123.327))
}
Output:
123
123.3
123.32
123.33
Here's one way you could do it:
fun func(x: Double): String {
if (x.rem(1).compareTo(0) == 0){
return x.toInt().toString();
} else {
return x.toString();
}
}
print(func(1.32132)); //Returns 1.32132
print(func(3.00)); //Returns 3
You could use DecimalFormat with setMaximumFractionDigits. Creating an extension function would keep the complexity away from the call-site:
fun Double.toStringRounded(fracDigits: Int) = DecimalFormat().apply {
setMaximumFractionDigits(fracDigits)
}.format(this)
Usage:
3.14159.toStringRounded(2) // will be "3.14"

Add commas or point every 3 digits using kotlin

I want to add commas or point every 3 digit in EditText input.
Example :
input : 1000. Output : 1.000
input : 11000. Output : 11.000
If you are on the JVM you can use
"%,d".format(input)
which gives 11,000 for input 11000. Replace , with any delimiter you require.
If you want to use predefined number formats, e.g. for the current locale, use:
java.text.NumberFormat.getIntegerInstance().format(input);
Be also sure to check the other format instances, e.g. getCurrencyInstance or getPercentInstance. Note that you can use NumberFormat also with other locales. Just pass them to the get*Instance-method.
Some of the second variant can also be found here: Converting Integer to String with comma for thousands
If you are using it via Javascript you may be interested in: How do I format numbers using JavaScript?
Based on Splitframe answer above, did a simplified version (without the var):
fun Int.formatDecimalSeparator(): String {
return toString()
.reversed()
.chunked(3)
.joinToString(",")
.reversed()
}
And added some tests:
#Test
fun whenFormatDecimal_thenReturnFormatted() {
mapOf(
1 to "1",
12 to "12",
123 to "123",
1234 to "1,234",
12345 to "12,345",
123456 to "123,456",
1234567 to "1,234,567",
12345678 to "12,345,678",
123456789 to "123,456,789",
1234567890 to "1,234,567,890",
).forEach { (test, expected) ->
val result = test.formatDecimalSeparator()
assertEquals(expected, result)
}
}
In my case is a KMM project, and we don't support other languages, so it does the job. A better solution I would say to create an expect Util class and each platform implement the formatter taking account of the user Locale, etc.
System.out.println(NumberFormat.getNumberInstance(Locale.US).format(35634646));
This is a simple way that able you to replace default separator with any characters:
val myNumber = NumberFormat.getNumberInstance(Locale.US)
.format(123456789)
.replace(",", "،")
I used this for a non JVM Kotlin environment:
fun formatDecimalSeperators(number :String) :String {
var index = 1
return number
.takeIf { it.length > 3 }
?.reversed()
?.map { if (index++ % 3 == 0) "$it," else it }
?.joinToString("")
?.reversed()
?.removePrefix(",")
?: number
}
You can also use #Roland answer in Android String Resources to format it:
<string name="answer_count">%,01d answers</string>
For a method without getting Locale, you can use an extension to convert your Int into a formatted String like this below :
fun Int.formatWithThousandComma(): String {
val result = StringBuilder()
val size = this.toString().length
return if (size > 3) {
for (i in size - 1 downTo 0) {
result.insert(0, this.toString()[i])
if ((i != size - 1) && i != 0 && (size - i) % 3 == 0)
result.insert(0, "\'")
}
result.toString()
} else
this.toString()
}

How to use Kotlin to find whether a string is numeric?

I'd like to use a when() expression in Kotlin to return different values from a function. The input is a String, but it might be parsable to an Int, so I'd like to return the parsed Int if possible, or a String if it is not. Since the input is a String, I cannot use the is type check expression.
Is there any idiomatic way to achieve that?
My problem is what the when() expression should look like, not about the return type.
Version 1 (using toIntOrNull and when as requested)
fun String.intOrString(): Any {
val v = toIntOrNull()
return when(v) {
null -> this
else -> v
}
}
"4".intOrString() // 4
"x".intOrString() // x
Version 2 (using toIntOrNull and the elvis operator ?:)
when is actually not the optimal way to handle this, I only used when because you explicitly asked for it. This would be more appropriate:
fun String.intOrString() = toIntOrNull() ?: this
Version 3 (using exception handling):
fun String.intOrString() = try { // returns Any
toInt()
} catch(e: NumberFormatException) {
this
}
The toIntOrNull function in the kotlin.text package (in kotlin-stdlib) is probably what you're looking for:
toIntOrNull
fun String.toIntOrNull(): Int? (source)
Platform and version requirements: Kotlin 1.1
Parses the string as an Int number and returns the result or null if the string is not a valid representation of a number.
fun String.toIntOrNull(radix: Int): Int? (source)
Platform and version requirements: Kotlin 1.1
Parses the string as an Int number and returns the result or null if the string is not a valid representation of a number.
More information: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/to-int-or-null.html
Using let for one
fun isInteger(str: String?) = str?.toIntOrNull()?.let { true } ?: false
Simple and intuitive
fun isNumeric(str: String) = str.all { it in '0'..'9' }
As #coolMind point out, if you want to filter +/-
fun isNumeric(str: String): Boolean = str
.removePrefix("-")
.removePrefix("+")
.all { it in '0'..'9' }
The performance would be similar
If you want to check if it is numeric (Int) the string and do something a simple solution could be:
if (myString.toIntOrNull() != null) {
//Write your code you want to execute if myString is (Int)
} else {
//Write your code you want to execute if myString is (not Int)
}
Sharing Regex matches solution, repost from my answer here
Best suited solution if negative and positive number which can be formatted with '-' and '.'
below method returns true if formatted string number matches the regex pattern
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)
}
Above sample regex is only for US number formats but if you want to use EU number formats then just replace '.' with ',' in regex pattern string
Note:. if the numbers contain commas then just replace it while sending to this method or better form a regex pattern with commas in it.
I searched for the same and I found this answer so I have made my own version from the above answer:
//function to check strin is int or bull
fun String.intOrString(): Boolean{
val v = toIntOrNull()
return when(v) {
null -> false
else -> true
}
}

Compare String Kotlin

I'm studying kotlin, but I'm very disappointed, I can not compare two Strings.
What is the right way to compare.
btn_login.setOnClickListener {
val login = input_email.text.trim()
val pass = input_password.text.trim()
if( login.equals( pass ) ){
startActivity<MainActivity>()
}
if (login?.equals(other = pass)){
startActivity<MainActivity>()
}
if (login == pass){
startActivity<MainActivity>()
}
}
According to documentation for structual equality use ==. It is translated to a?.equals(b) ?: (b === null).
In you case convert login and pass from SpannableStringBuilder to String.
val login = input_email.text.trim().toString()
Here is the example for matching the two strings using kotlin.
If you are using == (double equals) for matching the string then it's compare the address & return maximum time wrong result as per java documentation so use equals for the same
If you want to use equal ignore case then pass the true in the equals method of String
if (s1.equals(s2,true))
other wise you can just use this without boolean like
if (s1.equals(s2,false)) or if (s1.equals(s2))
compleate code is below
fun main(args: Array<String>) {
val s1 = "abc"
val s2 = "Abc"
if (s1.equals(s2,true))
{
println("Equal")
}
else
{
println("Not Equal")
}
}
Covert both the SpannableStringBuilder to string with toString, this should work.
val login = input_email.text.trim().toString()
val pass = input_password.text.trim().toString()
if (login == pass){
startActivity<MainActivity>()
}
1. == :
if ( string1 == string2 ){...}
2. equals :
Indicates whether some other object is "equal to" this one.
Implementations must fulfil the following requirements:
Reflexive: for any non-null reference value x, x.equals(x) should
return true.
Symmetric: for any non-null reference values x and y, x.equals(y)
should return true if and only if y.equals(x) returns true.
Transitive: for any non-null reference values x, y, and z, if
x.equals(y) returns true and y.equals(z) returns true, then
x.equals(z) should return true
Consistent: for any non-null reference values x and y, multiple
invocations of x.equals(y) consistently return true or consistently
return false, provided no information used in equals comparisons on
the objects is modified.
/** * Returns `true` if this string is equal to [other], optionally ignoring character case. * * #param ignoreCase `true` to ignore character case when comparing strings. By default `false`. */
public fun String?.equals(other: String?, ignoreCase: Boolean = false): Boolean
3. compareTo :
public override fun compareTo(other: String): Int
Compares this object with the specified object for order. Returns zero
if this object is equal to the specified other object, a negative
number if it's less than other, or a positive number if it's greater
than other.
public fun String.compareTo(other: String, ignoreCase: Boolean = false): Int
Compares two strings lexicographically, optionally ignoring case
differences
i know this is way too late, but as a newbie learning Kotlin, i had the same doubts.
then i came across this wonderful article that articulates the various string comparison types in Kotlin and the differences between them all.
in short both == and .equals() can be used to compare the value of 2 strings in kotlin.
hopefully that helps
With case checking
String a=.....
String b=.....
if(a==b){
}
IgnoreCase
if(a.equals(b,false))
KOTLIN:
if (editText1.text.toString() == editText2.text.toString() ) {
println("Should work now! The same value")
}
Try the following solution, see if it helps:
val passStr: String = textView.text.toString()
if( loginStr.compareTo(passStr, false) ){
startActivity<MainActivity>()
}
Try this surely will work.
val style = buildString { karthik}
val style2 = buildString { karthik }
var result = style.equals(style2)
if(result){//Do something}