I'm wondering is there some method or methods combo that could obtain these results.
What I meant is that you have a string ex. "Hello world, how are you?"
And I want to achieve following functionality, to get start and end index of substring
in that string.
ex. substring = "world", and start index would be 6, and end index 10
Is there something like this in standard kotlin libraries?
Something like this?
val s = "Hi there"
val substringToFind = "there"
val start = s.indexOf(substringToFind)
val end = start + substringToFind.length
println(s.substring(start,end))
output: there
Maybe you could just use indexOf assuming you just want the first occurence:
fun main(args: Array<String>) {
val str = "Hello world, how are you?"
val sub = "world"
println(getStartAndEndOfSubstring(str, sub))
}
fun getStartAndEndOfSubstring(str: String, sub: String): Pair<Int, Int> {
val start = str.indexOf(sub)
when (start != -1) {
true -> return Pair(start, start + sub.length - 1)
false -> return Pair(-1, -1)
}
}
Output:
(6, 10)
Related
Programming Language: KOTLIN
I'm trying to make a function which adds two numbers in the following way..
a^i+b^i where "i" would be the iterator in for loop. So I want the i to range from 1 to 10 and print the result one by one like this... for example if I give the values as a=1 & b=2 then the result must be calculated as..
a^1+b^1= 1^1+2^1 which gives 3 so print the result.
a^2+b^2= 1^2+2^2 which gives 6 and print the result.
etc., repeating the process until "i" becomes 10.
so I tried the following code and it only prints the result of initial values.
fun main(){
println(test(22,33))
}
fun test(a:Int,b:Int):Int{
var result1=1
var result2=1
var result3=result1+result2
for(i in 1..10){
result1*=a
result2*=b
result3=a+b
println(result3)
}
return result3
}
You were only adding the parameters of your function for result3. This works though:
fun addWithIteratedPower(a: Int, b: Int) : Int {
var resultA = 1
var resultB = 1
var combinedResult = 0
for(i in 1..10){
resultA *= a
resultB *= b
combinedResult = resultA + resultB
println(combinedResult)
}
return combinedResult
}
And here's a test that validates it:
#Test
fun `should return final combined result`(){
val oneAndTwoToPowerOfTenAdded = (1.0.pow(10) + 2.0.pow(10)).toInt()
assertThat(addWithIteratedPower(1, 2)).isEqualTo(oneAndTwoToPowerOfTenAdded)
}
How can we split a text between two char in Kotlin?
Example string:
base_id:94, user_id: 320903, is_Active=1
I want to get only user_id so "320903". But I couldn't do that.
One way to get it is using regex and you can customize it to cover base_id and is_Active
val pattern = Pattern.compile("user_id: (?<id>[0-9]+)")
val matcher = pattern.matcher(text)
if (matcher.find()) {
val group = matcher.group("id").trim()
println(group)
}
The output will be : 320903
Or you can do that with split only and you will get the same result
val items = text.split(",")
val userId = items[1].split(":")[1].trim()
println(userId)
That will work correctly with your example but make sure but for other cases, you may need to customize it or give us many examples to cover them
You can handle the 3 values with one function that support optional whitespace and : or =
fun getValueByTagName(text : String, tag : String) : String {
val pattern = Pattern.compile("$tag[:=][ ]*(?<id>[0-9]+)")
val matcher = pattern.matcher(text)
return if (matcher.find())
matcher.group("id").trim()
else ""
}
To use it
println(getValueByTagName(text, "base_id")) // 94
println(getValueByTagName(text, "user_id")) // 320903
println(getValueByTagName(text, "is_Active")) // 1
Another solution:
Method 1: If your string has exactly the same format that you have shown in the example.
val indexOfUserId = s.indexOf("user_id") // find index of the substring "user_id"
val end = s.indexOf(',', indexOfUserId) // find index of ',' after user_id
val userId s.substring(indexOfUserId + 9, end) // take the substring assuming that userId starts exactly 9 characters after the "u" in "user_id"
Method 2: If your format can vary (in spaces and symbols). Also assuming that user_id is always a number.
val indexOfUserId = s.indexOf("user_id")
val start = s.findAnyOf(List(10) { "$it" }, indexOfUserId)!!.first // find the first digit after "user_id"
val userId = s.substring(start).takeWhile { it.isDigit() } // start from the first digit and continue as long as you are getting digits
Here, List(10) { "$it" } is just a list of all digits in string format and findAnyOf:
Finds the first occurrence of any of the specified [strings] in this char sequence, starting from the specified [startIndex]
Try it yourself
Given that we have returned separately a list of animals:
val animals = "cat, dog and mouse"
Which we then concat to our animalsMessage so it looks as following:
val animalsMessage = "You have identified cat, dog and mouse"
Given my default font colour is white and I only wanted to change the val animals font colour in my animalsMessage, I could do:
animalsMessage.setSpan(
ForegroundColorSpan(resources.getColor(R.color.yellow, null)),
animalsMessage.length - animals.length,
animalsMessage.length,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)
However, say I wanted to ignore the , and the word and whilst spanning, so they remained the default white colour, how would I go about doing that? I am basing this question on the assumption that there might be an and in the animals string and there might be one , or many.
I believe the answer lies in using a pattern matcher and then ignoring whilst spanning based on finding a match.
Things I have tried:
First, before concat my val animals to my val animalsMessage I tried to format my val animals as described above, to do that, I created the below method:
private fun ignoreSeparators(animals: String): SpannableString {
val spannable = SpannableString(animals)
val matcher: Matcher = Pattern.compile(",\\\\and").matcher(animals)
while (!matcher.matches()) {
val animal = matcher.group(1)
val animalIndex: Int = animals?.indexOf(animal) - 1
spannable.setSpan(ForegroundColorSpan(resources.getColor(R.color.yellow, null)), 0, animalIndex, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
}
return spannable
}
I then planned on returning the spanned text and then concating it to my val animalsMessage, however, I get a crash saying that no match is found.
I would recommend doing the following, first, remove the , and and change to a list as follows...
val animals = listOf("cat", "dog", "mouse")
Then, pass them to the following method that will handle the styling, followed by adding the necessary comma and the and. The rule followed was that the and would always be between the last and second from last animal and all other values no matter how large the list is, would be separated by a comma.
The second param, prefix, is simply our animalsMessage which we concat to, as mentioned in your question.
private fun formatAnimalStrings(animals: List<String>, prefix: String): SpannableStringBuilder {
val lastIndex = animals.size - 1
val secondLastIndex = lastIndex - 1
val result = SpannableStringBuilder(prefix)
animals.forEachIndexed { index, animal ->
val startIndex = result.length
result.append(animals[index])
result.setSpan(
ForegroundColorSpan(resources.getColor(R.color.yellow, null)),
startIndex,
startIndex + animal.length,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)
if (index < lastIndex) {
if (index == secondLastIndex) {
result.append(" and ")
} else {
result.append(", ")
}
}
}
result.append(".")
return result
}
This would result in
You have identified cat, dog and mouse
(I have used bold to express yellow text colour, since I cannot make the text yellow)
String example (not necessary A and B, but not X): AAAXBBXBXBBB
I want to find all occoruncaes of X and save them in an array.
I wrote a function:
val arrayList = ArrayList<Int>()
fun findAllX(str: String){
for(i in 0 until str.length){
if(str[i] == 'X'){
arrayList.add(i)
}
}
}
Result in this example: arrayList that contains integers 3, 6, 8
Is there a better/cleaner way to write this?
Here is a one-liner:
"AAAXBBXBXBBB".withIndex().filter { it.value == 'X' }.map { it.index }.toTypedArray()
In Kotlin how to parse a double or float number from string like this:
var st: String? = "90 min"
tried to use toDoubleOrNull but always returns 0 or null.
If you are certain that the number is always at the start, then use split() with space as delimiter and from the returned list take the 1st item and parse it to Double:
val value = st!!.split(" ")[0].toDoubleOrNull()
If there is a case of spaces at the start or in between, use this:
val value = st!!.trim().split("\\s+".toRegex())[0].toDoubleOrNull()
And another way with substringBefore():
val value = st!!.trim().substringBefore(" ").toDoubleOrNull()
Or if there is only 1 integer number in the string, remove every non numeric char with replace():
val value = st!!.replace("\\D".toRegex(), "").toDoubleOrNull()
You can try (assuming you have only one sequence of numbers in your string).
Otherwise, check other answers
val inputString = "123. Test"
val regex = "\\d+(\\.\\d+)?".toRegex()
val match = regex.find(inputString)
if (match != null) {
println("Result: " + match.value)
} else {
println("Result: Not found")
}
This should work...
val pattern = Pattern.compile("\\d+") // the regex
val matcher = pattern.matcher("hello123hgj") // your string
val doubles = ArrayList<Double>() // results
while (matcher.find())
{ // for each match
doubles.add(Double.parseDouble(matcher.group())) // convert to double
}
It depends on what you need. If you just have to get 90 and the string is formatted always in the same way you can just
var string = "90 min"
var floatFromString = string.substring(0,2).toFloat()
but it's better to learn how to use LocalDate and DateTimeFormatter