androidkotlinandroid-edittextword-counttextchanged

how to handle new line in word count?


i'm referring this answer https://stackoverflow.com/a/42802060/12428090

basically my goal is to handle word count of 100 words the abve solution works fine for typed 100 words and even handles copy paste very well

but it doesnt handles the new line case suppose in entered word or copy pasted word contains new line then the word count is returning incorrect

following is the code please help out

    override fun onTextChanged(s: CharSequence, start: Int, before: Int, 
       count: Int) {
    val wordsLength: Int = countWords(s.toString()) // words.length;
    limitmoderator.text = "$wordsLength/$MAX_WORDS"
    val yourText: String =
        moderator_intro.getText().toString().replace(160.toChar().toString(), " ")
    if (yourText.split("\\s+".toRegex()).size > MAX_WORDS) {
        var space = 0
        var length = 0
        for (i in 0 until yourText.length) {
            if (yourText[i] == ' ') {
                space++
                if (space >= MAX_WORDS) {
                    length = i
                    break
                }
            }
        }
        if (length > 1) {
            moderator_intro.getText()
                .delete(length, yourText.length) // deleting last exceeded words
            setCharLimit(moderator_intro, length - 1) //limit edit text
        }
    } else {
        removeFilter(moderator_intro)
    }}


 private fun countWords(s: String): Int {
 val trim = s.trim()
 return if (trim.isEmpty()) 0 else trim.split("\\s+".toRegex()).size
 // separate string around spaces
    }

    private var filter: InputFilter? = null

    private fun setCharLimit(et: EditText, max: Int) {
filter = LengthFilter(max)
et.filters = arrayOf<InputFilter>(filter as LengthFilter)
     }

    private fun removeFilter(et: EditText) {
    if (filter != null) {
    et.filters = arrayOfNulls(0)
     filter = null
      }
    }
       

so i have tried rplacing the "\n" in the text but it doesnt seems to be handling the case properly

any help will be appreciated

thanks in advance


Solution

  • Here's a different strategy than the one from the question you linked. Notice I'm using afterTextChanged and not onTextChanged!

    I'm manually counting words to get the character index of the first whitespace after the last allowable word. That way I don't have to trim and then use Regex, and then try to figure out the index offset of that Regex. Then instead of applying a temporary filter, I directly cut the end of the Editable off.

    editText.setSelection is to keep the cursor from jumping to the beginning.

    override fun afterTextChanged(s: Editable) {
        var previousWasWhitespace = true
        var i = 0
        var wordCount = 0
        for (c in s) {
            val whitespace = c.isWhitespace()
            if (whitespace && !previousWasWhitespace && ++wordCount == MAX_WORDS) {
                break
            }
            previousWasWhitespace = whitespace
            i++
        }
    
        if (i < s.length) {
            s.delete(i, s.length)
            editText.setSelection(i)
        }
    }