NumberFormatException in converting string to byte - kotlin

I am trying to get the MD5 format of string
Code:
fun getEncodedData(data: String): String? {
val MD5 = "MD5"
// Create MD5 Hash
val digest = java.security.MessageDigest
.getInstance(MD5)
digest.update(data.toByte())
val messageDigest = digest.digest()
// Create Hex String
val hexString = StringBuilder()
for (aMessageDigest in messageDigest) {
var h = Integer.toHexString(0xFF and aMessageDigest.toInt())
while (h.length < 2)
h = "0$h"
hexString.append(h)
}
return hexString.toString()
}
There is a crash at: digest.update(data.toByte()). I get number format Exception
Input I am passing for data: oEXm43
There is no crash if I pass ex: 11 as a string for input data
Should the input always should be integer in the string or can it be a mixture of number and characters.

You're trying to call the update method that takes a single byte parameter, and using toByte which converts the entire string's numerical value to a single byte. This conversion method is what fails on non-numerical values inside a String.
Instead, you can use the variant of update with a byte[] parameter, and convert your String to an array of bytes (one per character) with toByteArray:
digest.update(data.toByteArray())

Related

Kotlin convert hex string to ByteArray

I have this string:
val s = "00b44a0bc6303782b729a7f9b44a3611b247ddf1e544f8b1420e2aae976003219175461d2bd7" +
"6e64ba657d7c9dff6ed7b17980778ec0cbf75fc16e52463e2d784f5f20c1691f17cdc597d7a514108" +
"0809a38c635b2a62082e310aa963ca15953894221ad54c6b30aea10f4dd88a66c55ab9c413eae49c0b" +
"28e6a3981e0021a7dcb0759af34b095ce3efce78938f2a2bed70939ba47591b88f908db1eadf237a7a" +
"7100ac87130b6119d7ae41b35fd27ff6021ac928273c20f0b3a01df1e6a070b8e2e93b5220ad0210400" +
"0c0c1e82e17fd00f6ac16ef37c3b6153d348e470843a84f25473a51f040a42671cd94ffc989eb27fd42" +
"b817f8173bfa95bdfa17a2ae22fd5c89dab2822bcc973b5b90f8fadc9b074cca8f9365b1e8994ff0bda48" + "b1f7498cce02d4e794915f8a4208de3eaf9fbff5"
Which is hexadecimal notation of bytes, hardcoded in as string format.
I need this thing as a bytearray, importantly, not the ASCII representation of it, actually the hexadecimal values that is represents.
All the kotlin methods I can find, such as:
val b = s.encodeToByteArray()
Seem to be taking the actual ASCII value of the string, and converting it to a bytearray.
How do I create a bytearray directly from the values in this string?
You can handle it like this:
fun String.decodeHex(): ByteArray {
check(length % 2 == 0) { "Must have an even length" }
return chunked(2)
.map { it.toInt(16).toByte() }
.toByteArray()
}
Split the string into 2-character pairs, representing each byte.
Parse each hex pair to their integer values.
Convert the parsed Ints to Bytes.
My other answer is the simplest way, but it creates two intermediate lists - a list of strings and a list of bytes - before it creates the byte array. Here are two slightly more complex versions that are more efficient.
This version uses sequences to take advantage of lazy evaluation. It still produces a string for every byte, but uses no intermediate lists.
fun String.decodeHex(): ByteArray {
check(length % 2 == 0) { "Must have an even length" }
val byteIterator = chunkedSequence(2)
.map { it.toInt(16).toByte() }
.iterator()
return ByteArray(length / 2) { byteIterator.next() }
}
This version uses the JDK's java.lang.Integer.parseInt function. It creates the ByteArray directly with no intermediate data-structures.
fun String.decodeHex(): ByteArray {
check(length % 2 == 0) { "Must have an even length" }
return ByteArray(length / 2) {
Integer.parseInt(this, it * 2, (it + 1) * 2, 16).toByte()
}
}

Convert String which is "float" to Integer

How to convert a string value which contains float representation to integer in kotlin?
I tried to convert string to float with .toFloat() and then converted it to an integer using toInt() and it works flawlessly.
But how to convert such string to integer directly?
val strDemo = "42.22"
val intDemo = strDemo.toInt()
snippet above throws NumberFormatException because it is not correct number representaion of Integer.
But, when I try
val strDemo = "42.22"
val intDemo = strDemo.toFloat().toInt()
it converts the data with no exception because string gets converted to float first. And there is a correct number representation for a Float value.
Now how to bypass the toFloat() method and convert strDemo to Integer directly?
There's no magic function that will convert a decimal/float string numbers to integer directly. It has to be done this way. Even if you found one, I'm sure that the process toFloat().toInt() still happen on that function.
So the solution that you can do is to create an extension of String like this:
StringExt.kt
fun String.floatToInt(): Int {
return this.toFloat().toInt()
}
You can use it like this:
val strDemo = "42.22"
val intDemo = strDemo.floatToInt()

Convert Hex value to Base64 using Kotlin

I have this value:
263e5df7a93ec5f5ea6ac215ed957c30
When I fill this in on: https://8gwifi.org/base64Hex.jsp (Hex to Base64)
It gives me back:
Jj5d96k+xfXqasIV7ZV8MA==
This is the expected value. However, when I try this in Kotlin,
val encodedHexB64 = Base64.encodeToString("263e5df7a93ec5f5ea6ac215ed957c30".toByteArray(UTF_8), Base64.NO_WRAP)
It gives me back:
MjYzZTVkZjdhOTNlYzVmNWVhNmFjMjE1ZWQ5NTdjMzA=
How to get the correct value in Kotlin?
To complete the previous:
val input = "263e5df7a93ec5f5ea6ac215ed957c30"
val bytes = input.chunked(2).map { it.toInt(16).toByte() }.toByteArray()
val encodeBase64 = Base64.encodeToString(bytes, Base64.DEFAULT)
Now you have: Jj5d96k+xfXqasIV7ZV8MA==
It looks like the input string represents 16 bytes, where each byte is coded with two hex digit chars of that string.
On the contrary toByteArray(UTF_8) encodes the string in UTF-8 encoding turning each char into one or more bytes. When you convert these bytes to base64, first you get the longer result and second — these are completely different bytes.
I suppose the correct way to convert the input hex string into byte array would be:
val input = "263e5df7a93ec5f5ea6ac215ed957c30"
val bytes = input.chunked(2).map { it.toInt(16).toByte() }.toByteArray()
Then you encode these bytes to base64 as usual.

What happens with toInt()

I currently start to learn Kotlin and I was making this code
val a = "1"
val b = a[0]
val c = b.toInt()
println(c)
When I run the code, the result is 49. What really happened? Because I think the result will be 1.
a is a String, which is a CharSequence. That is why you can access a[0] in the first place. a.get(0) or a[0] then returns a Char. Char on the other hand returns its character value when calling toInt(), check also the documentation of toInt().
So your code commented:
val a = "1" // a is a String
val b = a[0] // b is a Char
val c = b.toInt() // c is (an Int representing) the character value of b
If you just want to return the number you rather need to parse it or use any of the answers you like the most of: How do I convert a Char to Int?
(one simple way being b.toString().toInt()).
a is String,
when you get a[index] return type is char,
in kotlin char.toInt method return ASCII code of the character and it's 49
if you want to get the integer value of "1" just use toString method
val a = "1"
val b = a[0].toString()
val c = b.toInt()
println(c)
prints:1
In your example a is a String, but String. String is under the hood an Array of Char. And by accessing your String using a[0] operator, you get first element of this Char Array. So you get Char '1', not String "1". And now, when you run '1'.toInt() function on Char - it will return ASCII code of that Char. When you run "1".toInt() on String - it will convert this String into Int "1". When you need to get Int value of first letter in your String, you need to convert it first into String:
val a = "123"
val b = a[0].toString() // returns first Char of String "123" and converts to String
val c = b.toInt() // returns Int: 1
or in one line:
"123"[0].toString().toInt()

How to convert String to Long in Kotlin?

So, due to lack of methods like Long.valueOf(String s) I am stuck.
How to convert String to Long in Kotlin?
1. string.toLong()
Parses the string as a [Long] number and returns the result.
#throws NumberFormatException if the string is not a valid
representation of a number.
2. string.toLongOrNull()
Parses the string as a [Long] number and returns the result or null
if the string is not a valid representation of a number.
3. string.toLong(10)
Parses the string as a [Long] number and returns the result.
#throws NumberFormatException if the string is not a valid
representation of a number.
#throws IllegalArgumentException when
[radix] is not a valid radix for string to number conversion.
public inline fun String.toLong(radix: Int): Long = java.lang.Long.parseLong(this, checkRadix(radix))
4. string.toLongOrNull(10)
Parses the string as a [Long] number and returns the result or null
if the string is not a valid representation of a number.
#throws IllegalArgumentException when [radix] is not a valid radix for string
to number conversion.
public fun String.toLongOrNull(radix: Int): Long? {...}
5. java.lang.Long.valueOf(string)
public static Long valueOf(String s) throws NumberFormatException
String has a corresponding extension method:
"10".toLong()
Extension methods are available for Strings to parse them into other primitive types. Examples below:
"true".toBoolean()
"10.0".toFloat()
"10.0".toDouble()
"10".toByte()
"10".toShort()
"10".toInt()
"10".toLong()
Note: Answers mentioning jet.String are outdated. Here is current Kotlin (1.0):
Any String in Kotlin already has an extension function you can call toLong(). Nothing special is needed, just use it.
All extension functions for String are documented. You can find others for standard lib in the api reference
Actually, 90% of the time you also need to check the 'long' is valid, so you need:
"10".toLongOrNull()
There is an 'orNull' equivalent for each 'toLong' of the basic types, and these allow for managing invalid cases with keeping with the Kotlin? idiom.
It's interesting. Code like this:
val num = java.lang.Long.valueOf("2");
println(num);
println(num is kotlin.Long);
makes this output:
2
true
I guess, Kotlin makes conversion from java.lang.Long and long primitive to kotlin.Long automatically in this case. So, it's solution, but I would be happy to see tool without java.lang package usage.
In Kotlin, to convert a String to Long (that represents a 64-bit signed integer) is simple.
You can use any of the following examples:
val number1: Long = "789".toLong()
println(number1) // 789
val number2: Long? = "404".toLongOrNull()
println("number = $number2") // number = 404
val number3: Long? = "Error404".toLongOrNull()
println("number = $number3") // number = null
val number4: Long? = "111".toLongOrNull(2) // binary
println("numberWithRadix(2) = $number4") // numberWithRadix(2) = 7
With toLongOrNull() method, you can use let { } scope function after ?. safe call operator.
Such a logic is good for executing a code block only with non-null values.
fun convertToLong(that: String) {
that.toLongOrNull()?.let {
println("Long value is $it")
}
}
convertToLong("123") // Long value is 123
One good old Java possibility what's not mentioned in the answers is java.lang.Long.decode(String).
Decimal Strings:
Kotlin's String.toLong() is equivalent to Java's Long.parseLong(String):
Parses the string argument as a signed decimal long. ... The
resulting long value is returned, exactly as if the argument and the
radix 10 were given as arguments to the parseLong(java.lang.String, int) method.
Non-decimal Strings:
Kotlin's String.toLong(radix: Int) is equivalent to Java's eLong.parseLong(String, int):
Parses the string argument as a signed long in the radix specified by
the second argument. The characters in the string must all be digits of the specified radix ...
And here comes java.lang.Long.decode(String) into the picture:
Decodes a String into a Long. Accepts decimal, hexadecimal, and octal
numbers given by the following grammar: DecodableString:
(Sign) DecimalNumeral | (Sign) 0x HexDigits | (Sign) 0X HexDigits | (Sign) # HexDigits | (Sign) 0 OctalDigits
Sign: - | +
That means that decode can parse Strings like "0x412", where other methods will result in a NumberFormatException.
val kotlin_toLong010 = "010".toLong() // 10 as parsed as decimal
val kotlin_toLong10 = "10".toLong() // 10 as parsed as decimal
val java_parseLong010 = java.lang.Long.parseLong("010") // 10 as parsed as decimal
val java_parseLong10 = java.lang.Long.parseLong("10") // 10 as parsed as decimal
val kotlin_toLong010Radix = "010".toLong(8) // 8 as "octal" parsing is forced
val kotlin_toLong10Radix = "10".toLong(8) // 8 as "octal" parsing is forced
val java_parseLong010Radix = java.lang.Long.parseLong("010", 8) // 8 as "octal" parsing is forced
val java_parseLong10Radix = java.lang.Long.parseLong("10", 8) // 8 as "octal" parsing is forced
val java_decode010 = java.lang.Long.decode("010") // 8 as 0 means "octal"
val java_decode10 = java.lang.Long.decode("10") // 10 as parsed as decimal
If you don't want to handle NumberFormatException while parsing
var someLongValue=string.toLongOrNull() ?: 0
Actually, there are several ways:
Given:
var numberString : String = "numberString"
// number is the Long value of numberString (if any)
var defaultValue : Long = defaultValue
Then we have:
+—————————————————————————————————————————————+——————————+———————————————————————+
| numberString is a valid number ? | true | false |
+—————————————————————————————————————————————+——————————+———————————————————————+
| numberString.toLong() | number | NumberFormatException |
+—————————————————————————————————————————————+——————————+———————————————————————+
| numberString.toLongOrNull() | number | null |
+—————————————————————————————————————————————+——————————+———————————————————————+
| numberString.toLongOrNull() ?: defaultValue | number | defaultValue |
+—————————————————————————————————————————————+——————————+———————————————————————+
string.toLong()
where string is your variable.