Search code examples
androidregexonclickspannablestring

Detect words that have @ or # and passing onClick event to it


Basically I have a string which looks like an instagram caption:

@username text text emoji@username2 #hastag text text #hastag2

The main issue here is that I could have a emoji in front of @ or # characters, so I need to parse the text and find the words even if they are surrounded by emoji. After a run I should have click event for @username,@username2,#hashtag and #hashtag2.

So far I did:

String caption = "@username text text emoji@username2 #hastag text text #hastag2";
SpannableString ss = new SpannableString(caption);
String[] words = caption.split(" ");

for (final String word : words) {

    if (word.startsWith("#") || word.startsWith("@")) {

        ClickableSpan clickableSpan = new ClickableSpan() {

            @Override
            public void onClick(View textView) {

                //Clicked word
                }
        };
        ss.setSpan(clickableSpan, caption.indexOf(word), caption.indexOf(word) + word.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
    }
}
txtComment.setText(ss);
txtComment.setMovementMethod(LinkMovementMethod.getInstance());

This does work for situations where there are no emoji envolved. How can I make this work on all scenarios ?


Solution

  • You need to create a regular expression Pattern, and then get a Matcher instance from it. Then you can iterate over the matches:

    Pattern p = Pattern.compile("[#@][a-zA-Z0-9]+"); //match letters or numbers after a # or @
    Matcher m = p.matcher(caption); //get matcher, applying the pattern to caption string
    while (m.find()) { // Find each match in turn
        ClickableSpan clickableSpan = new ClickableSpan() {
            @Override
            public void onClick(View textView) {
                //Clicked word
            }
        };
        ss.setSpan(clickableSpan, m.start(), m.end(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
    }
    

    If you want to include underscores, you can use the RegEx suggested by @anubhava (which is equivalent to [#@][a-zA-Z0-9_]+).