Home > Blockchain >  Unable to replace string inside a String in Kotlin
Unable to replace string inside a String in Kotlin

Time:04-02

I am trying to replace a few sub strings inside a string. But my code doesn't seem to work.

val listOfMaleWords = listOf(" him", " he", " his")
val listOfFemaleWords = listOf(" her", " she", " her")

fun modifyIdeaForGender(rawIdea : String, desiredGender : String): String {
    var theRawIdea = rawIdea
    if (desiredGender == "FEMALE") {
        println("desired gender is FEMALE")
        listOfMaleWords.forEachIndexed { index, element ->
            theRawIdea.replace(element, listOfFemaleWords[index])
        }
    } else {
        println("desired gender is MALE")
        listOfFemaleWords.forEachIndexed { index, element ->
            theRawIdea.replace(element, listOfMaleWords[index])
        }
    }
    return theRawIdea
}

fun main() {
    var sampleString : String = "Tell him, he is special"
    println(modifyIdeaForGender(sampleString, "FEMALE"))
}

Expected Output :

"Tell her, she is special"

Current Output :

"Tell him, he is special" // no change

Whats wrong with my code? The current output doesn't replace the string characters at all.

CodePudding user response:

replace returns a new String that you are discarding immediately. It does not mutate theRawIdea itself, so you should assign it back to theRawIdea yourself. For example:

theRawIdea = theRawIdea.replace(element, listOfFemaleWords[index])

Though this would modify theRawIdea as you desire, it wouldn't replace the pronouns correctly. Once it replaces the "him"s with "her"s, it would try to replace the "he"s with "she"s. But note that "he" a substring of "her"! So this would produce:

Tell sher, she is special

This could be fixed by reordering the lists, putting the "he"-"she" pair first, or by using regex, adding \b word boundary anchors around the words:

// note that you should not have spaces before the words if you decide to use \b
val listOfMaleWords = listOf("him", "he", "his")
val listOfFemaleWords = listOf("her", "she", "her")

...

theRawIdea = theRawIdea.replace("\\b$element\\b".toRegex(), listOfFemaleWords[index])

Note that this doesn't account for capitalisation or the fact that changing from female gender pronouns to male ones is inherently broken. Your current code would change all her to him. It would require some more complicated natural language processing to accurately do this task in general.

Taking all that into account, I've rewritten your code with zip:

fun modifyMaleIdeaToFemaleGender(rawIdea : String): String {
    var theRawIdea = rawIdea
    // if you really want to do the broken female to male case, then this would be
    // listOfFemaleWords zip listOfMaleWords
    // and the loop below can stay the same
    val zipped = listOfMaleWords zip listOfFemaleWords
    zipped.forEach { (target, replacement) -> 
        theRawIdea = theRawIdea.replace("\\b$target\\b".toRegex(), replacement) 
    }
    return theRawIdea
}

You can also use fold to avoid reassigning theRawIdea:

fun modifyIdeaToFemaleGender(rawIdea : String): String {
    val zipped = listOfMaleWords zip listOfFemaleWords
    return zipped.fold(rawIdea) { acc, (target, replacement) ->
        acc.replace("\\b$target\\b".toRegex(), replacement)
    }
}

CodePudding user response:

Your code assumes that the replace() method performs an in-place mutation of the string. However, the string with the replaced values are returned by the replace(). So you need to change your code to contain something like:

theRawIdea = theRawIdea.replace(element, listOfFemaleWords[index])

To do this, you will have to use a conventional loop instead of listOfMaleWords.forEachIndexed style looping.

  • Related