How to change styles for all numbers in strings (from strings.xml) to (small) and (subscript) and (color.blue)? and where put that in recyclerView adapter (all strings in Array)?
Like this:
If you are using Kotlin, use regex to replace all the numbers with HTML formatting.
var text = "This is an example of text[1] formatting."
"\\[[0-9]+\\]".toRegex().findAll(text)
.flatMap { it.groupValues }
.forEach {
val num = it.drop(1).dropLast(1)
text = text.replace(it, "<sup>[$num]</sup>")
}
Then use tvMyTextView.setText(Html.fromHtml(text))
Related
I'm not sure I worded the question correctly.
I have a set of variables, that go like: STO1, STO2, STO3.....STO9; and I need to get the user to input the digit to store and to recall those memory addresses.
So is there a way that the 'STO' be concatenated to the digit (1...9) to get to the var name?
The var names are declared already. I just need to either store a value or retrieve it.
I know that in other languages that is indirect addressing, I think.
Thanks in advance for any input.
Ray.
If variables defined insisde the class (so they are properties) it can be done via Reflection Api.
class Example {
var sto1 = "s1"
var sto2 = "s2"
}
fun main() {
val obj = Example()
val userInput = "1"
val prop = Example::class.memberProperties.find { it.name == "sto$userInput"}
prop as KMutableProperty<*>
//get value example
println(prop.get(obj))
//set value example
prop.setter.call(obj, "new value")
println(prop.get(obj))
}
In order to compile it you should add kotlin-reflect lib to your maven/gradle project.
I'm trying to write some test cases for my compose functions.
I have an outlined Text field with a maximum value of 16 characters.
So I want to test this feature. Here is the test:
#Test
fun checkMaxTaxCodeLength_16Character() {
val taxCode = composeRule.onNodeWithTag(testTag = AUTHENTICATION_SCREEN_TAX_CODE_EDIT_TEXT)
for (i in 'A'..'Z')
taxCode.performTextInput(i.toString())
taxCode.assertTextEquals("ABCDEFGHIJKLMNOP")
}
But although I can see the input is correct, the test fails, and it seems assertTextEquals doesn't work correctly. So:
first of all, what am I doing wrong?
Second, is there any way to, instead of checking the equality, check the text does not contain specific characters?
here is the code of text field:
OutlinedTextField(
value = state.taxCode,
maxLines = 1,
onValueChange = { string ->
viewModel.onEvent(
AuthenticationEvent.TaxCodeChanged(string)
)
},
label = {
Text(text = stringResource(id = R.string.tax_code))
},
modifier = Modifier
.fillMaxWidth()
.testTag(TestingConstant.AUTHENTICATION_SCREEN_TAX_CODE_EDIT_TEXT)
)
The maximum length is handled in the view model. If the user adds more characters than 16, the view model won't update the state and keep the old value.
first of all, what am I doing wrong?
assertTextEquals() takes the value of Text and EditableText in your semantics node combines them and then does a check against the values you pass in. The order does not matter, just make sure to pass in the value of the Text as one of the arguments.
val mNode = composeTestRule.onNodeWithText("Email"))
mNode.performTextInput("test#mail.com")
mNode.assertTextEquals("Email", "test#mail.com")
Please note the text Email is the label for the textfield composable.
To get the semantic information about your nodes you can have
#Test
fun print_semantics_tree() {
composeTestRule.onRoot(useUnmergedTree = true).printToLog(TAG)
}
For the TAG you can use any string. After running the above test you can search the logcat with the specified TAG. You should see something like
|-Node #3 at (l=155.0, t=105.0, r=925.0, b=259.0)px
| Focused = 'false'
| ImeAction = 'Default'
| EditableText = 'test#mail.com'
| TextSelectionRange = 'TextRange(0, 0)'
| Text = '[Email]'
| Actions = [RequestFocus, GetTextLayoutResult, SetText, SetSelection,
OnClick, OnLongClick, PasteText]
Please note you can also obtain the semantics node object with an index operation rather than iterating through all the values.
val value = fetchSemanticsNode().config[EditableText]
assertEquals("test#mail.com", value.toString())
Ok, still, the problem is open, but I achieved what I wanted another way. I used semantic nodes to get what is in edit text and compared it with what it should be:
#Test
fun checkMaxTaxCodeLength_16Character() {
val taxCode = composeRule.onNodeWithTag(testTag = AUTHENTICATION_SCREEN_TAX_CODE_EDIT_TEXT)
for (i in 'A'..'Z')
taxCode.performTextInput(i.toString())
for ((key,value) in taxCode.fetchSemanticsNode().config)
if (key.name =="EditableText")
assertEquals("ABCDEFGHIJKLMNOP",value.toString())
}
I have a mutable list of strings and I'm trying to remove a word from each of them. The problem is that I don't believe the word is being removed from each line.
for (item in stringLines) {
when {
item.contains("SUMMARY") -> eventLines.add(item)
item.contains("DTSTART") -> startDateLines.add(item)
item.contains("DTEND") -> endDateLines.add(item)
//item.contains("URL:") -> locationLines.add(item)
//item.contains("CATEGORIES") -> categoriesLines.add(item)
}
}
for (item in eventLines) {
when{
item.contains("SUMMARY") -> item.removePrefix("SUMMARY")
}
}
The string is
SUMMARY WINTER FORMAL
and I need
WINTER FORMAL
but whatever reason it just doesn't appear. I know how to do this in java but I have no idea how to do this in Kotlin and I could not find any function that was able to accomplish this. What am I missing?
removePrefix removes the specific part of the string only if that is the prefix. Obviously, this is not your case. You could do a split, filter, join sequence to yield your expected result.
println("SUMMARY WINTER FORMAL".split(" ").filter { it != "SUMMARY" }.joinToString(" "))
//output : "WINTER FORMAL"
But if you have multiple contiguous spaces, they will become one space in the output. Also this method does not work if "SUMMARY" is not surrounded by spaces, e.g. "SUMMARYWINTERFORMAL" won't be changed.
You can remove part of the string by replacing it with empty string, but note that this will keep any surrounding characters including the surrounding spaces.
println("SUMMARY WINTER FORMAL".replace("SUMMARY",""))
//output : " WINTER FORMAL"
Note that there is a space in front of "WINTER"
If you wan't to include the spaces if any, using Regular Expression would do:
println("SUMMARY WINTER FORMAL".replace("\\s*SUMMARY\\s*".toRegex(),""))
//output : "WINTER FORMAL"
println("SUMMARYWINTERFORMAL".replace("\\s*SUMMARY\\s*".toRegex(),""))
//output : "WINTERFORMAL"
println(" SUMMARY WINTER FORMAL".replace("\\s*SUMMARY\\s*".toRegex(),""))
//output : "WINTER FORMAL"
You can modify the regular expression even more to better suit your use case.
Strings in Kotlin (and Java) are immutable. So item.removePrefix returns a new String and you have to update the list or create a new list like this:
for (item in eventLines) {
when {
item.contains("SUMMARY") ->
eventLinesWithPrefixRemoved.add(item.removePrefix("SUMMARY"))
else -> eventLinesWithPrefixRemoved.add(item)
}
}
If you want only to remove 'SUMMARY' from the string, you can use this case
val l = listOf("SUMMARY WINTER FORMAL", "SUMMARY FORMAL", "WINTER FORMAL", "SUMMARY WINTER")
println(
l.map {
it.split(" ")
.filter { s -> s != "SUMMARY" }
.joinToString(" ")
}
) // puts [WINTER FORMAL, FORMAL, WINTER FORMAL, WINTER]
I'm trying to store certain lines from an .ics file to separate strings depending on their contents. I've been able to convert an .ics file to a string, but I am having difficulty searching it line by line to find certain keywords.
The string (and file) contains:
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//School of Rochester NY |-ECPv4.8.1//NONSGML v1.0//EN
CALSCALE:GREGORIAN
METHOD:PUBLISH
X-WR-CALNAME:School of Rochester NY |
I've been able to display the text in the logcat, but I have not been able to save the lines as separate strings.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
var textView = findViewById<TextView>(R.id.textView)
val file_name = "education-1e1a4bdab8e.ics"
val ics_string = application.assets.open(file_name).bufferedReader().use {
it.readText()
}
Log.i("TAG", ics_string)
textView.text = ics_string
if (ics_string.contains("BEGIN:VCALENDAR", ignoreCase = true))
{
Log.i("TAG", "contains event")
}
}
The logcat confirms that the text is in the document, but not which line.
Is there any way to add lines of a text as separate strings?
Just looking at the BufferedReader you have already 4 functions that all give you the lines.
readLines gives you a List<String> containing all the lines
useLines lets you use a sequence of lines which you can then transform and assures that after calling it, the reader is closed
lineSequence() returns a sequence of the lines, but does not close the reader after calling it
lines() returns a Stream<String> containing the lines and basically comes from the BufferedReader itself. As you are using Kotlin you probably do not want to use this method.
useLines and readLines are also available on File itself
As I am not sure what you really want to accomplish I recommend you start with readLines directly. The ics-file is usually rather small and with the lines you can still filter/map whatever you want. The next best candidate then is probably either useLines or lineSequence. It really depends on what you do next.
You can use the extension function on String, lines(), something like this:
fun lines() {
val text = """BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//School of Rochester NY |-ECPv4.8.1//NONSGML v1.0//EN
CALSCALE:GREGORIAN
METHOD:PUBLISH
X-WR-CALNAME:School of Rochester NY |"""
val foundLines = text.lines().map {
it.contains("BEGIN:VCALENDAR") to it
}.filter { (contains, _) -> contains }
.map { it.second }
println(foundLines)
}
fun main() {
lines()
}
So I have a textField where you should enter your "coded" text and get it translated back to non-coded language by using .replace to remove certain characters. But I can't get it to work.
There is a kids "code-language" where you take a word, like cat and for every consonant you add an "o" and the consonant again. So a "b" would be "bob". With vowels they just stay as they are. Cat would be cocatot.
fun translateBack(view : View) {
val konsonanter = "bcdfghjklmnpqrstvwxzBCDFGHJKLMNPQRSTVWXZ"
var input = editText.text.toString()
var emptyString = ""
for(i in konsonanter) {
val find_text = i + "o" + i
var conso = i.toString()
textView.text = input.replace(find_text, conso, false)
}
}
Would like for it to remove the two following letters for every consonant (if possible). So if i enter "cocowow" I should get out "cow". Right now I just get back what I enter in the textField...
Use a forEach loop through the chars of input and replace:
konsonanter.forEach { input = input.replace("${it}o${it}", "${it}", false) }
textView.text = input
The issue is that you're setting the text in textView in every loop, and never updating input. So you're essentially only seeing the result of the replace call that happens with the "ZoZ" and "Z" parameters at the end of the loop, with input still being the original string.
Instead, you can keep updating input and then set the text when you're done:
val konsonanter = "bcdfghjklmnpqrstvwxzBCDFGHJKLMNPQRSTVWXZ"
var input = editText.text.toString()
var emptyString = ""
for (i in konsonanter) {
val find_text = i + "o" + i
val conso = i.toString()
input = input.replace(find_text, conso, false)
}
textView.text = input
If you use the replace function with a Regex and a transform function as parameters you can create a really concise completely self-containing extension function:
fun String.translateBack() = with(Regex("([bcdfghjklmnpqrstvwxz])o\\1", RegexOption.IGNORE_CASE)) {
replace(this) { "${it.value.first()}" }
}
Explanation:
The Regex will match all same consonants (no matter the case) around an "o".
To ensure that the consonant before and after the "o" are the same a backreference to the first group was used.
So, this will also work for cases like "coCatot".
Usage:
println("bob".translateBack()) // b
println("cocatot".translateBack()) // cat
println("coCatot".translateBack()) // cat