skip to Main Content

What i aim to do is to create a bold text when some words or characters in a String wrapped with special characters such as ++bold++ displaying as bold with Jetpack Compose Text component as many times it’s available in a specific string.

val boldRegex = Regex("\*\*.*\*\*")

using this regex and the snippet below

@Composable
fun CustomText(text: String, modifier: Modifier = Modifier) {


    val boldKeywords: MatchResult? = boldRegex.find(text)

    val boldIndexes = mutableListOf<Pair<Int, Int>>()
    boldKeywords?.let {
        boldIndexes.add(Pair(it.range.first, it.range.last - 2))
    }

    val newText = text.replace("**", "")

    val annotatedString = buildAnnotatedString {
        append(newText)

        // Add bold style to keywords that has to be bold
        boldIndexes.forEach {
            addStyle(
                style = SpanStyle(
                    fontWeight = FontWeight.Bold,
                    color = Color(0xff64B5F6),
                    fontSize = 15.sp

                ),
                start = it.first,
                end = it.second
            )

        }
    }

    Text(
        modifier = modifier
            .fillMaxWidth()
            .padding(start = 8.dp, end = 8.dp, top = 12.dp, bottom = 12.dp),
        fontSize = 16.sp,
        text = annotatedString
    )
}

enter image description here

I get the result right only when an exact pattern exists once and not also it’s not correct replacing every occurrence of the character.

CustomText(text = "This is a **bold** text")

CustomText(
    text = "This is a **bold** text  and another **random** value build with *regex expression"
)

CustomText(
    text = "This is NOT a ****bold** text build with *regex expression"
)

CustomText(
    text = "This is NOT a **bold text build with *regex expression"
)
  • In first text result is as desired
  • In second one it should only make bold and random substrings as bold
  • In third one it should not have any bold substrings and no
    replacement
  • In fourth one there should be no bold substrings and no replacements

I checked this regex question but i wasn’t able to come up with correct regex to divide into groups and replacing pattern with

2

Answers


  1. Chosen as BEST ANSWER

    Thanks to @Wiktor Stribiżew's help with regex i came up with a solution but i don't think it's efficient as i expect it to be. If you come up with better solution feel free to add a new answer.

    val boldRegex = Regex("(?<!\*)\*\*(?!\*).*?(?<!\*)\*\*(?!\*)")
    
    
    @Composable
    fun CustomText(text: String, modifier: Modifier = Modifier) {
    
        var results: MatchResult? = boldRegex.find(text)
    
        val boldIndexes = mutableListOf<Pair<Int, Int>>()
    
        val keywords = mutableListOf<String>()
    
        var finalText = text
    
        while (results != null) {
            keywords.add(results.value)
            results = results.next()
        }
    
        keywords.forEach { keyword ->
            val indexOf = finalText.indexOf(keyword)
            val newKeyWord = keyword.removeSurrounding("**")
            finalText = finalText.replace(keyword, newKeyWord)
            boldIndexes.add(Pair(indexOf, indexOf + newKeyWord.length))
        }
    
        val annotatedString = buildAnnotatedString {
            append(finalText)
    
            // Add bold style to keywords that has to be bold
            boldIndexes.forEach {
                addStyle(
                    style = SpanStyle(
                        fontWeight = FontWeight.Bold,
                        color = Color(0xff64B5F6),
                        fontSize = 15.sp
    
                    ),
                    start = it.first,
                    end = it.second
                )
    
            }
        }
    
        Text(
            modifier = modifier
                .fillMaxWidth()
                .padding(start = 8.dp, end = 8.dp, top = 12.dp, bottom = 12.dp),
            fontSize = 16.sp,
            text = annotatedString
        )
    }
    

    I think it can be solved without using a second loop but couldn't find it.

    Result for

    Column() {
        CustomText(text = "This is a **bold** text")
    
        CustomText(
            text = "This is a **bold** text and another **random** value **build** with *regex expression"
        )
    
        CustomText(
            text = "This is NOT a ****bold** text build with *regex expression"
        )
    
        CustomText(
            text = "This is NOT a **bold text build with *regex expression"
        )
    }
    

    enter image description here


  2. I did some modifications on you answer using less code and for loops, You may check this

    val boldRegex = Regex("(?<!\*)\*\*(?!\*).*?(?<!\*)\*\*(?!\*)")
    
    
    @Composable
    fun TextWithBoldStrings(
        modifier: Modifier = Modifier,
        text: String,
        regularFontSize: TextUnit = 16.sp,
        boldSpanStyle: SpanStyle = SpanStyle(
            fontWeight = FontWeight.Bold,
            color = Color(0xff64B5F6),
            fontSize = 15.sp
        )
    ) {
    
        val keywords = boldRegex.findAll(text).map { it.value }.toList()
    
        val annotatedString = buildAnnotatedString {
            var startIndex = 0
            keywords.forEach { keyword ->
                val indexOf = text.indexOf(keyword)
                append(text.substring(startIndex, indexOf))
                startIndex = indexOf + keyword.length
                val newKeyWord = keyword.removeSurrounding("**")
                withStyle(
                    style = boldSpanStyle
                ) {
                    append(newKeyWord)
                }
            }
            append(text.substring(startIndex, text.length))
    
        }
    
        Text(
            modifier = modifier,
            fontSize = regularFontSize,
            text = annotatedString
        )
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search