Split space from string not working in Kotlin - android

Anyone wonder this ? Splitting SPACE (" ") in kotlin is not working, i tried with different regex codes but is not working at all.
Tried with this :
value.split("\\s")[0];
value.split("\\s+")[0];
value.split("\\s++")[0];
Then i came up with solution -> Create java constant class which contains this function and returns string array to your kotlin class.
Is there any other solution for this problem where we can directly achieve this thing?
Solution : As #Edson Menegatti said :
KOTLIN Specific : WORKING
values.split("\\s".toRegex())[0]
Many people suggested this solution : NOT WORKING
values.split(" ")[0]
But in my case it's not working.

Here's an issue between the Java and Kotlin implementation of String.split.
While the Java implementation does accept a regex string, the Kotlin one does not. For it to work, you need to provide an actual Regex object.
To do so, you would update your code as follows:
value.split("\\s".toRegex())[0]
Also, as #Thomas suggested, you can just use the regular space character to split your string with:
value.split(" ")[0]
Final point, if you're only using the first element of the split list, you might want to consider using first() instead of [0] - for better readability - and setting the limit parameter to 2 - for better performance.

You need to use :
.toRegex()
fun main(args: Array<String>) {
val str = "Kotlin com"
val separate1 = str.split("\\s".toRegex())[0]
println(separate1) // ------------------> Kotlin
}
OR
You can also use .split(" ")[0] to achieve result. Like
fun main(args: Array<String>) {
val str = "Kotlin com"
val separate1 = str.split(" ")[0]
println(separate1) // ----------> Kotlin
}

String#split (actually CharSequence#split) can take either a regular expression, or just a string which is interpreted literally. So:
value.split(" ")[0]
does what you want.
If you're only using the first element, it's more efficient to also pass limit = 2. Or, even better, use substringBefore.

Kotlin tries to resolve some issues that Java's String library has. For instance, Kotlin tries to be more explicit.
As a result, the split method takes a normal String and does not use it as a regex internally:
"hello world".split("\\s")[0] //no match
"hello world".split(" ")[0] // => "hello"
To explicitly use the overloaded split function that actually takes a regex, the toRegex() extension can be used (inline fun String.toRegex(): Regex (source)):
"hello world".split("\\s".toRegex())[0]// => "hello"
The following shows another example of Kotlin resolving the confusing String::replaceAll method:
Taken from a KotlinConf presentation of Svetlana Isakova, co-author of “Kotlin in Action”

Single delimiter
val splittedStringList = "123.345-80A".split(".")
println(splittedStringList[0])
Several delimiters
println("123.345-80A".split(".", "-"))
Using regex
println("123.345-80A".split("\\.|-".toRegex()))
Try Kotlin Online

Simply use value.split("\s".toRegex())
1.Splits and iterates all items
value.split("\\s".toRegex()).forEach { item ->
//use item
}
2.Spits and use first item
value.split("\\s".toRegex()).first()
3.Spits and use last item
value.split("\\s".toRegex()).last()

Related

Is there a way to convert a string into literal code that you can use in Kotlin?

This might be a very silly question, but I am logging the methods that are triggered in my app as strings. When an issue is submitted, I would like to automatically input the text of the strings as parameters for methods. E.g:
For method:
fun assignPot(potType: PotType, ball: DomainBall, action: PotAction) {...}
I'd like to somehow call method:
assignPot(FOUL(2, BLUE(5), SWITCH))
From String:
"FOUL(2, BLUE(5), SWITCH)"
The only workaround I can think of is to split the string and create a when -> then function to get actual classes from strings, but I wondered if there's a more concise way for this.
This is not what you want to do. You should design your app in a way that prevents users from providing input similar to actual code.
However, you can achieve this. Complex parsings like this oftenly use regex-based approaches.
As you said, you should map your string part to class. If your PotType is enum, you can do something like
val re = Regex("[^A-Za-z\s]")
val reNumbers = Regex("[^0-9\s]")
// get classes
val classNames = originalString.replace(re, "").split(" ")
// get their constructor numerical arguments
val classArgs = originalString.replace(reNumbers, "").split(" ")
After that you can implement mapping with when expression. You probably will use some collection of Any type.
As you see, this sadly leads you to parsing code by code. Concise way to solve is to implement your own script compiler/interpreter and use it in your application :) That will later lead you to dealing with security breaches and so on.
If you are logging problematic method calls and want to repeat them immediately after issue is submitted, you probably want to programatically save the calls to lambdas and call them when you receive an issue log.

Set property type from specific class as parameter type

I have this sample data class:
data class Car ( var id: String )
Now I can create a fun as this:
fun doWhatever(id: String){}
My problem is that if my customer then tells me that Id is an int, I have to change it in both places.
So what I want is to set Car.id type as refence in fun doWhatever, something like this:
fun doWhatever(id: propertyTypeOfCarId){}
So I if the customer changes type, I only have to change it in the class.
I read all kind of posts, but I wasnt able to find the answer. Any idea how to achieve it?
If this isn't something you expect to be doing regularly, consider just using the refactoring tools the IDE provides. You code to handle a specific set of data, and if the structure of that data changes, you have to adapt the code to fit it. Baking in a bunch of "what if" functionality can add complexity, compared to just saying a String is a String and changing it if it ever needs changing, using the tools provided to make that as quick and easy as possible.
But sometimes you need to do this kind of thing, and Kotlin has some nice language features it can be worth using, like type aliases:
typealias CarId = String
data class Car(var id: CarId)
fun doWhatever(id: CarId){}
Two benefits here: the actual type is only defined in one place, so you can change that String to an Int without needing to change anything else - except stuff that relied on the ID being a String specifically of course
The other benefit is you're actually adding some semantic information by using that very specific type. That function isn't supposed to just take any old String - it's specifically meant to handle CarIds. It tells you what it's for, and that can make your code a lot easier to understand
(The function will accept Strings, because CarId is just an alias - an alternative name for a String - so it's not a way to enforce structure on your code, just a way to make it nicer to read and write. You can't define a new type that is a String in Kotlin unfortunately)
If the number of id types you support is limited, you can simply use method overloading:
fun doWhatever(id: String){}
fun doWhatever(id: Int){}
// etc.
Alternatively, you can use a reified generic parameter in your method to support any number of types:
inline fun <reified T> doWhatever(id: T) {
when (T::class) {
Int::class -> {}
String::class -> {}
}
}

what does it. mean in the context of alos operator

I am learning how to use the coroutines in kotlin. looking at some examples in the internet i found that within the context f the also operator the reference
it
is used. i could not find any explanation about the meaning of
it
please provide some brief explanantion about what does "it" mean
when you use the also method, it has 1 parameter.
Think of it in Java kinda like this:
foo.also(int it) {
// do stuff
}
In Kotlin, the it parameter is implicit (sometimes you might want to use it sometimes you don't).
If you want to rename it to something more readable you can
foo.also { newName ->
// do stuff with newName
}
Or just use it like it is
foo.also {
// do stuff with $it
}
So therefore when you are using a method (or a closure/lambda) if it has 1 parameter, then the implicit name of that parameter is always it.
Basically it represents the lambda parameter
let's say you want to perform anything on the variable but do to check the nullity first, you can do it like
var str:String?=null // str is of string type
now you can use it fail safe
str?.let{it:String// youll see like this
// now you can access str as **it**
}
it is the implicit name of a single parameter
For more information about it and this in scoping functions like also

Kotlin apply on String not working as expected

I am trying to use all features of kotlin, but seems not of them are working, or may be it's my fault.
So, apply to String not work. Example:
val str = someStr.apply {
toUpperCase()
if (contains("W")) replace("W", "w")
}
Input -> xywz
Output -> xywz
Expected -> XYwZ
Java style:
val str = it.text().toString().toUpperCase()
if (str.contains("W")) str.replace("W", "w")
Input -> xywz
Output -> XYwZ
Expected -> XYwZ
Am I doing something wrong?
Actually apply does not return the value you calculated. You may rather want to use either: run, let or with. Additionally, probably more important, is that you do not specify an else path. That might return you a Unit instead of a value, so you may want to specify what should be returned otherwise. Finally, the calls within those methods are not chained. Calling toUpperCase first doesn't alter anything... It's nearly dead code... So you may want to write something like:
val str = with(someStr) {
toUpperCase().run {
if (contains("W")) replace("W", "w")
else this
}
}
However I just used run/let/with to demonstrate its usage, as you already used apply... your shown Java way is of course way easier in this regard and the simplest possible solution is rather the one TheOperator showed by just omitting your condition in the first place as the replace is case-sensitive by default.
toUpperCase() returns a copy of the string (strings are immutable). So you need to store the returned value, as a stand-alone (not last) statement inside apply() it is lost.
Also, you can't use if without else, if you return an expression. The contains() is not even needed in your case.
What you probably would like to do is call toUpperCase() and replace() directly:
val str = someStr.toUpperCase().replace("W", "w")
Docs of "apply" :
Calls the specified function block with this value as its receiver and
returns this value.
So it returns the original value ("this value").
What you should use is "let" instead:
val str = someStr.let {
it.toUpperCase().replace("W", "w")
}
But then you could just use:
val str = someStr.toUpperCase().replace("W", "w")

How to merge two sets of enums in kotlin having the same parent interface?

I'm trying to do the following:
val list = MyEnum1.values().filterIsInstance(MyParentInterface::class.java)
.plus(MyEnum2.values().filterIsInstance(MyParentInterface::class.java))
On Android Studio, lint is complaining that filterIsInstance is a "useless call on collection type". However, if I remove it, the plus(MyEnum2.values()... doesn't work because they are not of the same type.
Is that the right way to merge the values of two enums into a single list?
Edit: My enums look like this:
enum class MyEnum1 : MyParentInterface {
ENUM1_TYPE1, ENUM1_TYPE2
}
You can declare a list explicitly as MyParentInterface and then just add values of your Enums.
val result = mutableListOf<MyParentInterface>()
return result.plus(MyEnum1.values())
.plus(MyEnum2.values())
You can convert value arrays to lists and then concatenate them:
val sum: List<MyParentInterface> = MyEnum1.values().asList() + MyEnum2.values().asList()

Categories

Resources