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.
CodePudding user response:
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 Lists of Chars to check them.
val password: String = readln()
var numberCount: Int = 0
val numbers: List<Char> = ('0'..'9').toList()
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: List<Char> = ('0'..'9').toList()
val specialCharacters: List<Char> = 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)
}
CodePudding user response:
Your list is a list of String
s, but for (character in password)
loops over the Char
s in password
. So you're trying to see if one of the String
s 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 Char
s in password
and counting how many of them each character string contains. A String
is treated like an array of Char
s, 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 Char
s 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 String
s) then a Set
is ideal
CodePudding user response:
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"
} }