I was playing with the kotlin-native samples.
I wonder how I could get String from pinned ByteArray. Just want to print it in the console.
If you need a solution for the JVM, since stringFromUtf8 is only available for the native platform, use toString with a Charset as argument:
val byteArray = "Hello World".toByteArray(Charsets.UTF_8)
val str = byteArray.toString(Charsets.UTF_8)
If you specifically only want to target native, use Sin's solution.
It seems that this API has changed
Now just use this: string.toUtf8(start, end)
https://github.com/JetBrains/kotlin-native/commit/cba7319e982ed9ba2dceb517a481cb54ed1b9352#diff-45a5f8d37067266e27b76d1b68f01173
Legacy version:
Use stringFromUtf8
/**
* Converts an UTF-8 array into a [String]. Replaces invalid input sequences with a default character.
*/
fun ByteArray.stringFromUtf8(start: Int = 0, size: Int = this.size) : String =
stringFromUtf8Impl(start, size)
See here.
And if the byteArray is like CPointer<ByteVar> by interoperating C APIs, pleace use .toKString() in Kotlin-Native
The OKIO library has a helper method for this commonToUtf8String
One can simply copy the method code don't need to add the entire lib just for this.
Another solution that could be used everyone but especially makes sense looking for a Kotlin Multiplatform solution and using ktor library already is using io.ktor.utils.io.core.String function directly without adding extra third pary library or extra actual class implementation. For example:
Your build.gradle.kts for all platforms:
implementation("io.ktor:ktor-client-core:${Versions.ktor}")
implementation("io.ktor:ktor-client-android:${Versions.ktor}")
implementation("io.ktor:ktor-client-apache:${Versions.ktor}")
implementation("io.ktor:ktor-client-ios:${Versions.ktor}")
Then use it
io.ktor.utils.io.core.String(byteArray, offset, length, Charsets.UTF_8)
Related
How to solve an example in a string?
Let's say we have val example : String = "3+5"
So how do I solve this example? Or if val example : String = "3*5/3"
Two ways to achieve it:
Keval - 3rd party dependency
You can either use Keval.eval("(3+4)(2/8 * 5) % PI") or as an extension function on String, "(3+4)(2/8 * 5) % PI".keval(). This will return the calculated value as Double. For your example, "3*5/3".keval().
To use it, add implementation("com.notkamui.libs:keval:0.8.0") in dependencies in app level build.gradle file and sync gradle. Then, use it in any file as mentioned in the above para, put the cursor on the line and press Alt + Enter (or hover for suggestions) to import the necessary imports.
Look into its Readme.md on the provided link for more usage and implementation details.
Custom String parsing using BODMAS rule
You can split the string using the BODMAS rule, parse the split array as int/double, if it throws exception, it means the substring is an expression too, again split it using BODMAS, parse and perform the calculation.
I have a bunch of strings like these in my already existing and quit big template file:
Hello $World I say hello to $User, too
I was thinking I could somehow let kotlin parse/search&replace this file as a kotlin string, and I'd just have to set the variables World and User to get an evaluated string... How is this possible?
This is not a kotlin source file, but a file that's beeing read by my kotlin program.
Why I want to do this? I used bash's envsubst before, and had to move away from this, since things were getting too complicated. But now I have no easy way to replace strings in a file anymore...
Thanks
What you want is called a template engine.
You don't really need an eval (which would allow running a full Kotlin application from a String) in this case.
For example, FreeMarker templates use a syntax that's similar to Kotlin template Strings, so a template may look like this:
<h1>Welcome ${user}!</h1>
Then, from Kotlin, you can evaluate the template with a Map holding the template bindings (variables the template can use) like this:
val user = "joe"
val bindings = mapOf("user" to user)
val cfg = new Configuration(Configuration.VERSION_2_3_29)
cfg.directoryForTemplateLoading = File("/where/you/store/templates")
val template = cfg.getTemplate("test.ftlh")
// write the resolved template to stdout
val out = OutputStreamWriter(System.out)
template.process(bindings, out)
See a Java example here: https://freemarker.apache.org/docs/pgui_quickstart_all.html
There are many other template engines, and the KTor site lists a few:
https://ktor.io/docs/working-with-views.html
If you're using KTor, BTW, it makes it much easier to use template engines... your framework may even have similar.
Warning: Please see my other answer first: you probably don't want to run a full Kotlin script just to parse some text file with variables... use a template engine for that.
It's possible to execute Kotlin scripts, i.e. eval Kotlin code, but it requires that you basically ship the Kotlin compiler with your application.
This GitHub project, KtsRunner, for example, does that, so you can do this:
val scriptContent = "5 + 10"
val fromScript: Int = KtsObjectLoader().load<Int>(scriptContent))
println(fromScript)
// >> 15
It requires some hacking though, is very slow and it uses a bunch of Kotlin "internal" APIs to work.
See the full list of libraries this project uses here:
https://github.com/s1monw1/KtsRunner/blob/master/lib/build.gradle.kts#L21
A "proper" KEEP proposal (discussion here) exists to add first-class support for this in Kotlin, but it's not finalized yet.
Currently, it looks something like this:
fun evalFile(scriptFile: File): ResultWithDiagnostics<EvaluationResult> {
val compilationConfiguration = createJvmCompilationConfigurationFromTemplate<MainKtsScript>()
val evaluationConfiguration = createJvmEvaluationConfigurationFromTemplate<MainKtsScript>()
return BasicJvmScriptingHost().eval(scriptFile.toScriptSource(), compilationConfiguration, evaluationConfiguration)
}
But it'll probably change before being released.
Please help me convert this java code to kotlin, I try many times but I can't
ObjectStream<DocumentSample> bin
= ObjectStreamUtils.createObjectStream(categoryStreams.toArray(new ObjectStream[0]));
In Kotlin, you may use toTypedArray() to get an Array from a List:
categoryStreams.toTypedArray() //Array<ObjectStream<DocumentSample>>
Then, you can use spread operator to prefix the array and pass it to ObjectStreamUtils.createObjectStream():
val bin = ObjectStreamUtils.createObjectStream<DocumentSample>(*categoryStreams.toTypedArray())
Assuming the categoryStreams object is one of the Collection type(List, Set, etc.), you can call kotlin's extension method toTypedArray on it to get an array of the ObjectStream:
This should work:
val bin = ObjectStreamUtils.createObjectStream(categoryStreams.toTypedArray())
If the method accepts vararg of ObjectStream, then you can use spread operator * to spread array to vararg:
val bin = ObjectStreamUtils.createObjectStream(*categoryStreams.toTypedArray())
To convert Java file to Kotlin
On the main menu, point to Code menu.
Choose Convert Java File to Kotlin File.
Done.
In your case it converts to:
val bin = ObjectStreamUtils.createObjectStream(categoryStreams.toArray(arrayOfNulls<ObjectStream>(0)))
var bin = ObjectStreamUtils.createObjectStream(categoryStreams.toArray(arrayOfNulls(0)))
the above code is converted your code to kotlin.
It sounds like a type inference problem. Try the code below. I add the declaration for categoryStreams. Not sure how it is declared in your code. But this is a reasonable declaration from looking at the code on github.
val categoryStreams = arrayListOf<ObjectStream<DocumentSample>>()
val bin = ObjectStreamUtils.createObjectStream(categoryStreams.toArray(arrayOfNulls<ObjectStream<DocumentSample>>(0)))
The idea is to provide the correct type for inference (which the converter neglected to provide). The original java did not infer the type, it was an explicit cast.
How can I find the variable type in Kotlin?
In Java there is instanceof, but Kotlin does not exist:
val properties = System.getProperties() // Which type?
You can use the is operator to check whether an object is of a specific type:
val number = 5
if(number is Int) {
println("number is of type Int")
}
You can also get the type as String using reflection:
println(Int::class.simpleName) // "Int"
println(Int::class.qualifiedName) // "kotlin.Int"
Please note:
On the Java platform, the runtime component required for using the
reflection features is distributed as a separate JAR file
(kotlin-reflect.jar). This is done to reduce the required size of the
runtime library for applications that do not use reflection features.
If you do use reflection, please make sure that the .jar file is added
to the classpath of your project.
Source: https://kotlinlang.org/docs/reference/reflection.html#bound-class-references-since-11
You can use like this:
val value="value"
println(value::class.java.typeName)
you can get the class name with properties::class.simpleName
Just a minor detail between mentioned answers.
var x = "X"
println(x::class.simpleName) // prints String
This code uses Reflection under the hood when you decompile it to Java bytecode and it looks like this Reflection.getOrCreateKotlinClass(x.getClass()).getSimpleName()
var y = "Y"
println(y.javaClass.simpleName) // prints String
And this would compile down to y.getClass().getSimpleName() and it's about 50 milliseconds faster.
I am trying to use one of my defined functions that accepts a string yet the software won't compile.
fun passes(address: String) = Collections.frequency(addresses, address) <= CONNECTIONS_PER_IP
fun passes(remoteAddress: InetSocketAddress) = passes(remoteAddress.hostName)
I can't even call the string function using a custom string, for example passes("127.0.0.1").
None of the following functions can eb called with the arguments supplied.
passes(String) defined in abendigo.Firewall
passes(InetSocketAddress) defined in abendigo.Firewall
I presume you're using java.lang.String instead of kotlin.String in the Kotlin source code. Please use only kotlin.String instead, this is the type that string literals in Kotlin have (but in the bytecode it's still transformed to java.lang.String).
The issue was an import of java.lang.String. For some reason IntelliJ imported it.