7

I am new to android programing. I added a context menu to edittext. I wish to get the word under the cursor on long press.

I can get selected text by following code.

@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
    EditText edittext = (EditText)findViewById(R.id.editText1);
    menu.setHeaderTitle(edittext.getText().toString().substring(edittext.getSelectionStart(), edittext.getSelectionEnd()));
    menu.add("Copy");
}

edittext has some text e.g "Some text. Some more text". When the user clicks on "more", the cursor will be in some where in the word "more". When the user long presses the word I want to get the word "more" and other words under the cursor.

General Grievance
  • 4,555
  • 31
  • 31
  • 45
user934820
  • 1,162
  • 3
  • 17
  • 48
  • Alternate approach: Use `BreakIterator.getWordInstance()`. See https://stackoverflow.com/questions/42219292/how-does-breakiterator-work-in-android – Suragch Jun 17 '17 at 08:03

5 Answers5

8

There is better and simpler solution : using pattern in android

public String getCurrentWord(EditText editText) {
    Spannable textSpan = editText.getText();
    final int selection = editText.getSelectionStart();
    final Pattern pattern = Pattern.compile("\\w+");
    final Matcher matcher = pattern.matcher(textSpan);
    int start = 0;
    int end = 0;

    String currentWord = "";
    while (matcher.find()) {
        start = matcher.start();
        end = matcher.end();
        if (start <= selection && selection <= end) {
            currentWord = textSpan.subSequence(start, end).toString();
            break;
        }
    }

    return currentWord; // This is current word
}
Ali Mehrpour
  • 603
  • 8
  • 16
  • Need to initialize currentWord. `currentWord = "";`. Other than that, this is an excellent solution. – Chad Bingham Feb 16 '15 at 19:05
  • The most flexible solution out there. But I use "\w+(\-\w+)*" as the regex, as there are words containing hyphens. E.g. pay-per-view. – ka3ak Oct 07 '19 at 19:39
6
EditText et = (EditText) findViewById(R.id.xx);

int startSelection = et.getSelectionStart();

String selectedWord = "";
int length = 0;

for(String currentWord : et.getText().toString().split(" ")) {
    System.out.println(currentWord);
    length = length + currentWord.length() + 1;
    if(length > startSelection) {
        selectedWord = currentWord;
        break;
    }
}

System.out.println("Selected word is: " + selectedWord);
Mirco Widmer
  • 2,139
  • 1
  • 20
  • 44
3

Please try following code as it is optimized. Let me know if you has more specification.

//String str = editTextView.getText().toString(); //suppose edittext has "Hello World!" 
int selectionStart = editTextView.getSelectionStart(); // Suppose cursor is at 2 position
int lastSpaceIndex = str.lastIndexOf(" ", selectionStart - 1);
int indexOf = str.indexOf(" ", lastSpaceIndex + 1);
String searchToken = str.substring(lastSpaceIndex + 1, indexOf == -1 ? str.length() : indexOf);

Toast.makeText(this, "Current word is :" + searchToken, Toast.LENGTH_SHORT).show();
Gaurav Darji
  • 488
  • 5
  • 12
  • just a simple note the may not clear enough here, for anyone that think about handle this case: if I cursor position in the first word --> means the lastSpaceIndex will be -1 and never mind about that because when we substring the string we add +1 to the lastSpaceIndex --> means it will become 0 and it is the first index of the string. – Mina Samir Apr 21 '21 at 03:28
3

I believe that a BreakIterator is the superior solution here. It avoids having to loop over the entire string and do the pattern matching yourself. It also finds word boundaries besides just a simple space character (commas, periods, etc.).

// assuming that only the cursor is showing, no selected range
int cursorPosition = editText.getSelectionStart();

// initialize the BreakIterator
BreakIterator iterator = BreakIterator.getWordInstance();
iterator.setText(editText.getText().toString());

// find the word boundaries before and after the cursor position
int wordStart;
if (iterator.isBoundary(cursorPosition)) {
    wordStart = cursorPosition;
} else {
    wordStart = iterator.preceding(cursorPosition);
}
int wordEnd = iterator.following(cursorPosition);

// get the word
CharSequence word = editText.getText().subSequence(wordStart, wordEnd);

If you want to get it on a long press then just put this in the onLongPress method of your GestureDetector.

See also

Suragch
  • 484,302
  • 314
  • 1,365
  • 1,393
0

@Ali Thank you for providing your solution.

Here is an optimized variant, which does break if the word has been found.

This solution does not create a Spannable, because it is not needed to find the word.

@NonNull
public static String getWordAtIndex(@NonNull String text, @IntRange(from = 0) int index) {
    String wordAtIndex = "";

    // w = word character: [a-zA-Z_0-9]
    final Pattern pattern = Pattern.compile("\\w+");
    final Matcher matcher = pattern.matcher(text);

    int startIndex;
    int endIndex;

    while (matcher.find()) {
        startIndex = matcher.start();
        endIndex = matcher.end();

        if ((startIndex <= index) && (index <= endIndex)) {
            wordAtIndex = text.subSequence(startIndex, endIndex).toString();
            break;
        }
    }
    return wordAtIndex;
}

Example: Get the word at the current cursor position:

String text = editText.getText().toString();
int cursorPosition = editText.getSelectionStart();

String wordAtCursorPosition = getWordAtIndex(text, cursorPosition);

Use this instead if you want to find all connected characters (including punctuation):

// S = non-whitespace character: [^\s]
final Pattern pattern = Pattern.compile("\\S+");

Java regex documentation (regular-expression): https://docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html

droide_91
  • 197
  • 2
  • 6