Split character from string in Idiomatic way Kotlin - kotlin

Hey I am working in kotlin. I have one string in which I want to split into list from there where I should provide character. I'll explain in details
For example 1
val string = "Birth Control"
val searchText = "n"
Output
["Birth Co", "trol"]
For example 2
val string = "Bladder Infection"
val searchText = "i"
Actual Output
["Bladder ", "nfect", "on"]
Expect Output
["Bladder ", "nfection"]
I tried some code but example 1 is working fine but example 2 is not because I only want to split first occurrence.
val splitList = title?.split(searchText, ignoreCase = true)?.toMutableList()
splitList?.remove(searchText)
Can someone guide me how to solve this idiomatic way. Thanks

You miss the limit option of the split function. If you give it a value of 2 the result list will have a maximum of 2 entries:
val result = "Bladder Infection".split("i", ignoreCase = true, limit = 2)

Related

Convert String into list of Pairs: Kotlin

Is there an easier approach to convert an Intellij IDEA environment variable into a list of Tuples?
My environment variable for Intellij is
GROCERY_LIST=[("egg", "dairy"),("chicken", "meat"),("apple", "fruit")]
The environment variable gets accessed into Kotlin file as String.
val g_list = System.getenv("GROCERY_LIST")
Ideally I'd like to iterate over g_list, first element being ("egg", "dairy") and so on.
And then ("egg", "dairy") is a tuple/pair
I have tried to split g_list by comma that's NOT inside quotes i.e
val splitted_list = g_list.split(",(?=(?:[^\\\"]*\\\"[^\\\"]*\\\")*[^\\\"]*\$)".toRegex()).toTypedArray()
this gives me first element as [("egg", second element as "dairy")] and so on.
Also created a data class and tried to map the string into data class using jacksonObjectMapper following this link:
val mapper = jacksonObjectMapper()
val g_list = System.getenv("GROCERY_LIST")
val myList: List<Shopping> = mapper.readValue(g_list)
data class Shopping(val a: String, val b: String)
You can create a regular expression to match all strings in your environmental variable.
Regex::findAll()
Then loop through the strings while creating a list of Shopping objects.
// Raw data set.
val groceryList: String = "[(\"egg\", \"dairy\"),(\"chicken\", \"meat\"),(\"apple\", \"fruit\")]"
// Build regular expression.
val regex = Regex("\"([\\s\\S]+?)\"")
val matchResult = regex.findAll(groceryList)
val iterator = matchResult.iterator()
// Create a List of `Shopping` objects.
var first: String = "";
var second: String = "";
val shoppingList = mutableListOf<Shopping>()
var i = 0;
while (iterator.hasNext()) {
val value = iterator.next().value;
if (i % 2 == 0) {
first = value;
} else {
second = value;
shoppingList.add(Shopping(first, second))
first = ""
second = ""
}
i++
}
// Print Shopping List.
for (s in shoppingList) {
println(s)
}
// Output.
/*
Shopping(a="egg", b="dairy")
Shopping(a="chicken", b="meat")
Shopping(a="apple", b="fruit")
*/
data class Shopping(val a: String, val b: String)
Never a good idea to use regex to match parenthesis.
I would suggest a step-by-step approach:
You could first match the name and the value by
(\w+)=(.*)
There you get the name in group 1 and the value in group 2 without caring about any subsequent = characters that might appear in the value.
If you then want to split the value, I would get rid of start and end parenthesis first by matching by
(?<=\[\().*(?=\)\])
(or simply cut off the first and last two characters of the string, if it is always given it starts with [( and ends in )])
Then get the single list entries from splitting by
\),\(
(take care that the split operation also takes a regex, so you have to escape it)
And for each list entry you could split that simply by
,\s*
or, if you want the quote character to be removed, use a match with
\"(.*)\",\s*\"(.*)\"
where group 1 contains the key (left of equals sign) and group 2 the value (right of equals sign)

Read one or two variables alternately in one line

I have declared 2 variables to read from console but on other case i want to read just one of them but i can't.
My code:
print("Enter two numbers in format: {source base} {target base} (To quit type /exit) ")
val (sourceBase, targetBase) = readLine()!!.split(" ")
`I can't type /exit because i've got IndexOutOfBoundsException.
Any tips?
Edit: Thank you all for respond, especially lukas.j, it's working now.
Add a second element, an empty string, if the splitted readLine() contains less than 2 elements:
val (sourceBase, targetBase) = readLine()!!.split(" ").let { if (it.size < 2) it + "" else it }

how to read mutliple lines of string into one variable using readln() in kotlin?

example:
a variable
val str = readln().replace("[^A-Za-z0-9 ] \\s+".toRegex(),"").trim()
should read multiple lines of input value, input value will be like this
heading
----------
topic1
topic2
or like this
heading
-------
a) topic1
b) topic2
input may contain special characters or tabs or spaces we need to remove them also
I don't know what your Regex is trying to do, but that's not really your question.
How do you know when the user has finished their input - a special word or an empty line?
Assuming an empty line, here's how you can get all the content
println("Enter something:")
var lines = ""
do {
val line = readLine()
lines += "${clean(line)}\n"
} while (!line.isNullOrBlank())
println("User input:\n$lines")
private fun clean(line: String?): String? {
return line?.replace("[^A-Za-z0-9 ] \\s+".toRegex(),"")?.trim()
}

Make string starts with specified prefix in Kotlin

I am trying to find out the native way to concatenate prefix to string, but only in case, it was not.
This code checks the text variable and makes it start with "#".
val text = "123456"
val prefix = "#"
val textFormatted = (if (text.startsWith(prefix)) "" else prefix ) + text
I hope there are clean solutions somewhere in Kotlin
An alternative would be to use removePrefix:
val textFormatted = prefix + text.removePrefix(prefix)
Otherwise you could also keep the if but write it the following way to avoid extra parentheses and extra concatenation, and also make the code closer to the semantics:
val textFormatted = if (text.startsWith(prefix)) text else "$prefix$text"
But your solution works too.
You can use the string interpolation from the kotlin, example:
val text:String = "123456#123456"
val prefix:String = "#"
val interpolation:String = "#${text.removePrefix(prefix)}"

Specific regex in Kotlin

I created two functions .One checkUnit to get the unit from string and second whatU if input contains m u n p T g k to convert the input value .But there is some mismatch .
My pattern examples:
"m(O|h|F|s|H|A|V)" -this is for the m before unit this part needs improve
\b0-9.Ohm.(?<![0-9])\b" - this is for Ohm this part is wrong
val pattern = Regex(whatToFind)
val result = pattern.containsMatchIn(whatToFind)
This is for all invalid characters in input [A-EI-LNP-SUW-Za-gi-jloq-tw-zvV/ '$&+,{}:;=_\[]|`~?##"<>^*()%!-£€¥¢©®™¿÷¦¬×§¶°]
How to check if m is before Ohm and after number in string 100mOhm in regex Kotlin in more effective way ?
You can take a look at the Pattern documentation. There are several predefined character classes like \d+ for a digit. So you can use the following method:
boolean matched = Pattern.matches("\\d+mOhm", "100mOhm");
Or if you want to have the pattern for a longer time you can use the following method:
Pattern pattern = Pattern.compile("\\d+mOhm");
Matcher matcher = pattern.matcher("100mOhm");
boolean matched = matcher.matches();
If you want to use only Kotlin, you can use the following code:
val regex = "\\d+mOhm".toRegex()
val matched = regex.matches("100mOhm")
I found also a nice tutorial with more information about Koltin Regex.
This meets your requirement:
import java.util.Scanner
fun main() {
val scanner = Scanner(System.`in`)
val s = scanner.nextLine()
println("\\d+mOhm".toRegex().matches(s))
}
Perhaps you can modify it from here.