new dev bug: fixed issues with automatic word accepting
This commit is contained in:
parent
38ca93ab9f
commit
c8c484a570
12 changed files with 85 additions and 84 deletions
|
|
@ -172,7 +172,6 @@ public abstract class TypingHandler extends KeyPadHandler {
|
||||||
protected boolean onNumber(int key, boolean hold, int repeat) {
|
protected boolean onNumber(int key, boolean hold, int repeat) {
|
||||||
suggestionOps.cancelDelayedAccept();
|
suggestionOps.cancelDelayedAccept();
|
||||||
|
|
||||||
|
|
||||||
// In Korean, the next char may "steal" components from the previous one, in which case,
|
// In Korean, the next char may "steal" components from the previous one, in which case,
|
||||||
// we must replace the previous char with a one containing less strokes.
|
// we must replace the previous char with a one containing less strokes.
|
||||||
if (mInputMode.shouldReplaceLastLetter(key, hold)) {
|
if (mInputMode.shouldReplaceLastLetter(key, hold)) {
|
||||||
|
|
@ -183,7 +182,7 @@ public abstract class TypingHandler extends KeyPadHandler {
|
||||||
// First pass, analyze the incoming key press and decide whether it could be the start of
|
// First pass, analyze the incoming key press and decide whether it could be the start of
|
||||||
// a new word. In case we do accept it, we preserve the suggestion list instead of clearing,
|
// a new word. In case we do accept it, we preserve the suggestion list instead of clearing,
|
||||||
// to prevent flashing while the next suggestions are being loaded.
|
// to prevent flashing while the next suggestions are being loaded.
|
||||||
else if (mInputMode.shouldAcceptPreviousSuggestion(key, hold)) {
|
else if (mInputMode.shouldAcceptPreviousSuggestion(suggestionOps.getCurrent(), key, hold)) {
|
||||||
// WARNING! Ensure the code after "acceptIncompleteAndKeepList()" does not depend on
|
// WARNING! Ensure the code after "acceptIncompleteAndKeepList()" does not depend on
|
||||||
// the suggestions in SuggestionOps, since we don't clear that list.
|
// the suggestions in SuggestionOps, since we don't clear that list.
|
||||||
String lastWord = suggestionOps.acceptIncompleteAndKeepList();
|
String lastWord = suggestionOps.acceptIncompleteAndKeepList();
|
||||||
|
|
|
||||||
|
|
@ -153,7 +153,7 @@ abstract public class InputMode {
|
||||||
|
|
||||||
// Interaction with the IME. Return "true" if it should perform the respective action.
|
// Interaction with the IME. Return "true" if it should perform the respective action.
|
||||||
public boolean shouldAcceptPreviousSuggestion(String unacceptedText) { return false; }
|
public boolean shouldAcceptPreviousSuggestion(String unacceptedText) { return false; }
|
||||||
public boolean shouldAcceptPreviousSuggestion(int nextKey, boolean hold) { return false; }
|
public boolean shouldAcceptPreviousSuggestion(String currentWord, int nextKey, boolean hold) { return false; }
|
||||||
public boolean shouldReplacePreviousSuggestion(@Nullable String currentWord) { return Characters.PLACEHOLDER.equals(currentWord); }
|
public boolean shouldReplacePreviousSuggestion(@Nullable String currentWord) { return Characters.PLACEHOLDER.equals(currentWord); }
|
||||||
public boolean shouldAddTrailingSpace(boolean isWordAcceptedManually, int nextKey) { return false; }
|
public boolean shouldAddTrailingSpace(boolean isWordAcceptedManually, int nextKey) { return false; }
|
||||||
public boolean shouldAddPrecedingSpace() { return false; }
|
public boolean shouldAddPrecedingSpace() { return false; }
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ class Mode123 extends ModePassthrough {
|
||||||
@Override @NonNull public String toString() { return "123"; }
|
@Override @NonNull public String toString() { return "123"; }
|
||||||
|
|
||||||
@Override public int getSequenceLength() { return digitSequence.length(); }
|
@Override public int getSequenceLength() { return digitSequence.length(); }
|
||||||
@Override public boolean shouldAcceptPreviousSuggestion(int nextKey, boolean hold) { return true; }
|
@Override public boolean shouldAcceptPreviousSuggestion(String currentWord, int nextKey, boolean hold) { return true; }
|
||||||
|
|
||||||
private final ArrayList<ArrayList<String>> KEY_CHARACTERS = new ArrayList<>();
|
private final ArrayList<ArrayList<String>> KEY_CHARACTERS = new ArrayList<>();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -94,10 +94,10 @@ public class ModeBopomofo extends ModePinyin {
|
||||||
* In Bopomofo mode, the 0-key is not Spacebar, so we do not rely on the parents to handle accepting
|
* In Bopomofo mode, the 0-key is not Spacebar, so we do not rely on the parents to handle accepting
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean shouldAcceptPreviousSuggestion(int nextKey, boolean hold) {
|
public boolean shouldAcceptPreviousSuggestion(String currentWord, int nextDigit, boolean hold) {
|
||||||
String newSequence = digitSequence + (char)(nextKey + '0');
|
String newSequence = digitSequence + (char)(nextDigit + '0');
|
||||||
return hold
|
return hold
|
||||||
|| newSequence.startsWith(seq.CHARS_0_SEQUENCE)
|
|| newSequence.startsWith(seq.CHARS_0_SEQUENCE)
|
||||||
|| (newSequence.startsWith(seq.CHARS_1_SEQUENCE) && nextKey != Sequences.CHARS_1_KEY);
|
|| (newSequence.startsWith(seq.CHARS_1_SEQUENCE) && nextDigit != Sequences.CHARS_1_KEY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -340,7 +340,7 @@ class ModeCheonjiin extends InputMode {
|
||||||
* Used for analysis before processing the incoming pressed key.
|
* Used for analysis before processing the incoming pressed key.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean shouldAcceptPreviousSuggestion(int nextKey, boolean hold) {
|
public boolean shouldAcceptPreviousSuggestion(String currentWord, int nextKey, boolean hold) {
|
||||||
return
|
return
|
||||||
(hold && !digitSequence.isEmpty())
|
(hold && !digitSequence.isEmpty())
|
||||||
|| (nextKey != Sequences.CHARS_0_KEY && digitSequence.startsWith(seq.CHARS_0_SEQUENCE))
|
|| (nextKey != Sequences.CHARS_0_KEY && digitSequence.startsWith(seq.CHARS_0_SEQUENCE))
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,6 @@ import io.github.sspanak.tt9.languages.LanguageKind;
|
||||||
import io.github.sspanak.tt9.preferences.settings.SettingsStore;
|
import io.github.sspanak.tt9.preferences.settings.SettingsStore;
|
||||||
import io.github.sspanak.tt9.util.Logger;
|
import io.github.sspanak.tt9.util.Logger;
|
||||||
import io.github.sspanak.tt9.util.Text;
|
import io.github.sspanak.tt9.util.Text;
|
||||||
import io.github.sspanak.tt9.util.TextTools;
|
|
||||||
|
|
||||||
public class ModeIdeograms extends ModeWords {
|
public class ModeIdeograms extends ModeWords {
|
||||||
private static final String LOG_TAG = ModeIdeograms.class.getSimpleName();
|
private static final String LOG_TAG = ModeIdeograms.class.getSimpleName();
|
||||||
|
|
@ -107,7 +106,7 @@ public class ModeIdeograms extends ModeWords {
|
||||||
final Text text = new Text(currentWord);
|
final Text text = new Text(currentWord);
|
||||||
if (text.isEmpty() || text.startsWithWhitespace() || text.isNumeric() || !language.isValidWord(currentWord)) {
|
if (text.isEmpty() || text.startsWithWhitespace() || text.isNumeric() || !language.isValidWord(currentWord)) {
|
||||||
reset();
|
reset();
|
||||||
Logger.i(LOG_TAG, "Current word is empty, numeric or invalid. Nothing to accept.");
|
Logger.i(LOG_TAG, "Current word: '" + currentWord + "' is empty, numeric or invalid. Nothing to accept.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -122,7 +121,7 @@ public class ModeIdeograms extends ModeWords {
|
||||||
boolean lastDigitBelongsToNewWord = preserveWords && initialLength >= 2;
|
boolean lastDigitBelongsToNewWord = preserveWords && initialLength >= 2;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (!digitSequence.equals(seq.CHARS_0_SEQUENCE) && !digitSequence.equals(seq.CHARS_1_SEQUENCE)) {
|
if (!seq.isAnySpecialCharSequence(digitSequence)) {
|
||||||
lastAcceptedWord = currentWord;
|
lastAcceptedWord = currentWord;
|
||||||
lastAcceptedSequence = lastDigitBelongsToNewWord ? digitSequence.substring(0, initialLength - 1) : digitSequence;
|
lastAcceptedSequence = lastDigitBelongsToNewWord ? digitSequence.substring(0, initialLength - 1) : digitSequence;
|
||||||
|
|
||||||
|
|
@ -148,30 +147,8 @@ public class ModeIdeograms extends ModeWords {
|
||||||
return
|
return
|
||||||
digitSequence.length() > 1
|
digitSequence.length() > 1
|
||||||
&& predictions.noDbWords()
|
&& predictions.noDbWords()
|
||||||
&& !digitSequence.equals(seq.EMOJI_SEQUENCE)
|
&& !seq.isAnySpecialCharSequence(digitSequence)
|
||||||
&& !digitSequence.equals(seq.CHARS_1_SEQUENCE)
|
&& !digitSequence.startsWith(seq.EMOJI_SEQUENCE);
|
||||||
&& !digitSequence.equals(seq.CHARS_0_SEQUENCE);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean shouldAcceptPreviousSuggestion(int nextKey, boolean hold) {
|
|
||||||
if (digitSequence.isEmpty()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (super.shouldAcceptPreviousSuggestion(nextKey, hold)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
String nextSequence = digitSequence + (char)(nextKey + '0');
|
|
||||||
|
|
||||||
return
|
|
||||||
TextTools.containsOtherThan1(nextSequence)
|
|
||||||
&& (
|
|
||||||
nextSequence.endsWith(seq.EMOJI_SEQUENCE) || nextSequence.startsWith(seq.EMOJI_SEQUENCE) ||
|
|
||||||
nextSequence.endsWith(seq.CHARS_1_SEQUENCE) || nextSequence.startsWith(seq.CHARS_1_SEQUENCE)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -40,21 +40,6 @@ public class ModeKanji extends ModePinyin {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean shouldAcceptPreviousSuggestion(int nextKey, boolean hold) {
|
|
||||||
if (digitSequence.isEmpty()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
String nextSequence = digitSequence + (char)(nextKey + '0');
|
|
||||||
if (seq.isAnySpecialCharSequence(nextSequence)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return super.shouldAcceptPreviousSuggestion(nextKey, hold);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean validateLanguage(@Nullable Language newLanguage) {
|
public boolean validateLanguage(@Nullable Language newLanguage) {
|
||||||
return LanguageKind.isJapanese(newLanguage);
|
return LanguageKind.isJapanese(newLanguage);
|
||||||
|
|
|
||||||
|
|
@ -56,14 +56,14 @@ public class ModePinyin extends ModeIdeograms {
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean shouldAcceptPreviousSuggestion(int nextKey, boolean hold) {
|
public boolean shouldAcceptPreviousSuggestion(String currentWord, int nextDigit, boolean hold) {
|
||||||
// In East Asian languages, Space must accept the current word, or type a space when there is no word.
|
// In East Asian languages, Space must accept the current word, or type a space when there is no word.
|
||||||
// Here, we handle the case when 0-key is Space, unlike the Space hotkey in HotkeyHandler,
|
// Here, we handle the case when 0-key is Space, unlike the Space hotkey in HotkeyHandler,
|
||||||
// which could be a different key, assigned by the user.
|
// which could be a different key, assigned by the user.
|
||||||
if (!digitSequence.isEmpty() && !digitSequence.equals(seq.CHARS_0_SEQUENCE) && nextKey == Sequences.CHARS_0_KEY) {
|
if (nextDigit == Sequences.CHARS_0_KEY && !digitSequence.isEmpty() && !seq.isAnySpecialCharSequence(digitSequence)) {
|
||||||
ignoreNextSpace = true;
|
ignoreNextSpace = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.shouldAcceptPreviousSuggestion(nextKey, hold);
|
return super.shouldAcceptPreviousSuggestion(currentWord, nextDigit, hold);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -395,25 +395,36 @@ class ModeWords extends ModeCheonjiin {
|
||||||
* automatically. This is used for analysis before processing the incoming pressed key.
|
* automatically. This is used for analysis before processing the incoming pressed key.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean shouldAcceptPreviousSuggestion(int nextKey, boolean hold) {
|
public boolean shouldAcceptPreviousSuggestion(String currentWord, int nextDigit, boolean hold) {
|
||||||
if (hold) {
|
if (hold) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (digitSequence.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
} else if (
|
||||||
|
digitSequence.equals(seq.CUSTOM_EMOJI_SEQUENCE) ||
|
||||||
|
(seq.startsWithEmojiSequence(digitSequence) && nextDigit != Sequences.CHARS_1_KEY && nextDigit != Sequences.CUSTOM_EMOJI_KEY)
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// Prevent typing the preferred character when the user has scrolled the special char suggestions.
|
// Prevent typing the preferred character when the user has scrolled the special char suggestions.
|
||||||
// For example, it makes more sense to allow typing "+ " with 0 + scroll + 0, instead of clearing
|
// For example, it makes more sense to allow typing "+ " with 0 + scroll + 0, instead of clearing
|
||||||
// the "+" and replacing it with the preferred character.
|
// the "+" and replacing it with the preferred character.
|
||||||
boolean specialOrCurrency = digitSequence.equals(seq.CHARS_GROUP_0_SEQUENCE) || digitSequence.equals(seq.CHARS_GROUP_1_SEQUENCE);
|
// Also don't type the preferred character when viewing a group. In that case we obviously want to
|
||||||
boolean isWhitespaceAndScrolled = digitSequence.equals(seq.CHARS_0_SEQUENCE) && !stem.isEmpty();
|
// type a space after the character from the group.
|
||||||
if (nextKey == Sequences.CHARS_0_KEY && (isWhitespaceAndScrolled || specialOrCurrency)) {
|
boolean inGroup = digitSequence.equals(seq.CHARS_GROUP_0_SEQUENCE) || digitSequence.equals(seq.CHARS_GROUP_1_SEQUENCE);
|
||||||
|
boolean isWhitespaceAndScrolled = digitSequence.equals(seq.CHARS_0_SEQUENCE) && !suggestions.isEmpty() && !suggestions.get(0).equals(currentWord);
|
||||||
|
if (nextDigit == Sequences.CHARS_0_KEY && (isWhitespaceAndScrolled || inGroup)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final char lastDigit = digitSequence.charAt(digitSequence.length() - 1);
|
||||||
|
|
||||||
return
|
return
|
||||||
!digitSequence.isEmpty() && (
|
(nextDigit == Sequences.CHARS_0_KEY && lastDigit != Sequences.CHARS_0_CODE)
|
||||||
(nextKey == Sequences.CHARS_0_KEY && digitSequence.charAt(digitSequence.length() - 1) != Sequences.CHARS_0_CODE)
|
|| (nextDigit != Sequences.CHARS_0_KEY && lastDigit == Sequences.CHARS_0_CODE);
|
||||||
|| (nextKey != Sequences.CHARS_0_KEY && digitSequence.charAt(digitSequence.length() - 1) == Sequences.CHARS_0_CODE)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -432,13 +443,15 @@ class ModeWords extends ModeCheonjiin {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// punctuation breaks words, unless there are database matches ('s, qu', по-, etc...)
|
|
||||||
return
|
return
|
||||||
!digitSequence.isEmpty()
|
!digitSequence.isEmpty()
|
||||||
&& predictions.noDbWords()
|
&& predictions.noDbWords()
|
||||||
&& digitSequence.contains(seq.CHARS_1_SEQUENCE)
|
&& (
|
||||||
&& !digitSequence.startsWith(seq.EMOJI_SEQUENCE)
|
// when no custom emoji, assume the last digit is the beginning of a new word
|
||||||
&& Text.containsOtherThan1(digitSequence);
|
digitSequence.equals(seq.CUSTOM_EMOJI_SEQUENCE)
|
||||||
|
// punctuation breaks words, unless there are database matches ('s, qu', по-, etc...)
|
||||||
|
|| (digitSequence.contains(seq.CHARS_1_SEQUENCE) && !digitSequence.equals(seq.CHARS_1_SEQUENCE))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ abstract class TranscribedLanguage extends Language implements Comparable<Transc
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
(LanguageKind.isKorean(this) && TextTools.isHangul(word))
|
(LanguageKind.isKorean(this) && TextTools.isHangulText(word)) // because of the way Korean works, we only need to check if it's text.
|
||||||
|| (LanguageKind.isChinese(this) && TextTools.isChinese(word))
|
|| (LanguageKind.isChinese(this) && TextTools.isChinese(word))
|
||||||
|| (LanguageKind.isJapanese(this) && TextTools.isJapanese(word));
|
|| (LanguageKind.isJapanese(this) && TextTools.isJapanese(word));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -255,7 +255,7 @@ public class Text extends TextTools {
|
||||||
// In the writing systems that do not use spaces, the last group is not the last word, but
|
// In the writing systems that do not use spaces, the last group is not the last word, but
|
||||||
// it could be an entire sentence or a paragraph. That's why we assume an average word length
|
// it could be an entire sentence or a paragraph. That's why we assume an average word length
|
||||||
// of N letters
|
// of N letters
|
||||||
if (codePoints > MAX_WORD_LENGTH_NO_SPACE && (TextTools.isChinese(group) || TextTools.isJapanese(group) || TextTools.isThai(group))) {
|
if (codePoints > MAX_WORD_LENGTH_NO_SPACE && (TextTools.isChineseText(group) || TextTools.isJapaneseText(group) || TextTools.isThaiText(group))) {
|
||||||
return text.length() - gr.substringCodePoints(codePoints - 4, codePoints).length();
|
return text.length() - gr.substringCodePoints(codePoints - 4, codePoints).length();
|
||||||
} else {
|
} else {
|
||||||
return matcher.start();
|
return matcher.start();
|
||||||
|
|
|
||||||
|
|
@ -11,28 +11,27 @@ import java.util.regex.Pattern;
|
||||||
import io.github.sspanak.tt9.util.chars.Characters;
|
import io.github.sspanak.tt9.util.chars.Characters;
|
||||||
|
|
||||||
public class TextTools {
|
public class TextTools {
|
||||||
private static final Pattern CONTAINS_OTHER_THAN_1 = Pattern.compile("[02-9]");
|
|
||||||
private static final Pattern COMBINING_STRING = Pattern.compile("^\\p{M}+$");
|
private static final Pattern COMBINING_STRING = Pattern.compile("^\\p{M}+$");
|
||||||
private static final Pattern NEXT_IS_PUNCTUATION = Pattern.compile("^\\p{Punct}");
|
private static final Pattern NEXT_IS_PUNCTUATION = Pattern.compile("^\\p{Punct}");
|
||||||
private static final Pattern IS_CHINESE = Pattern.compile("\\p{script=Han}+");
|
private static final Pattern IS_CHINESE = Pattern.compile("[\\p{script=Han}" + String.join("", Characters.PunctuationChinese) + "]+");
|
||||||
private static final Pattern IS_JAPANESE = Pattern.compile("\\p{script=Hiragana}+|\\p{script=Katakana}+|\\p{script=Han}+");
|
private static final Pattern IS_HANGUL_TEXT = Pattern.compile("[\u1100-\u11FF\u302E-\u302F\u3131-\u318F\u3200-\u321F\u3260-\u327E\uA960-\uA97F\uAC00-\uD7FB\uFFA0-\uFFDF]+");
|
||||||
private static final Pattern IS_HANGUL = Pattern.compile("[\u1100-\u11FF\u302E-\u302F\u3131-\u318F\u3200-\u321F\u3260-\u327E\uA960-\uA97F\uAC00-\uD7FB\uFFA0-\uFFDF]+");
|
private static final Pattern IS_JAPANESE = Pattern.compile("[\\p{script=Hiragana}\\p{script=Katakana}\\p{script=Han}" + String.join("", Characters.PunctuationChinese) + "]+");
|
||||||
private static final Pattern IS_THAI = Pattern.compile("[\\u0E00-\\u0E7F]+");
|
private static final Pattern IS_CHINESE_TEXT = Pattern.compile("\\p{script=Han}+");
|
||||||
|
private static final Pattern IS_JAPANESE_TEXT = Pattern.compile("[\\p{script=Hiragana}\\p{script=Katakana}\\p{script=Han}]+");
|
||||||
|
private static final Pattern IS_THAI_TEXT = Pattern.compile("[\\u0E00-\\u0E7F]+");
|
||||||
private static final Pattern NEXT_TO_WORD = Pattern.compile("\\b$");
|
private static final Pattern NEXT_TO_WORD = Pattern.compile("\\b$");
|
||||||
private static final Pattern PREVIOUS_IS_LETTER = Pattern.compile("[\\p{L}\\p{M}](?!\\n)$");
|
private static final Pattern PREVIOUS_IS_LETTER = Pattern.compile("[\\p{L}\\p{M}](?!\\n)$");
|
||||||
private static final Pattern START_OF_SENTENCE = Pattern.compile("(?<!\\.)(^|[.?!؟¿¡])\\s+$");
|
private static final Pattern START_OF_SENTENCE = Pattern.compile("(?<!\\.)(^|[.?!؟¿¡])\\s+$");
|
||||||
|
|
||||||
|
|
||||||
public static boolean containsOtherThan1(String str) {
|
|
||||||
return str != null && CONTAINS_OTHER_THAN_1.matcher(str).find();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static boolean isCombining(String str) {
|
public static boolean isCombining(String str) {
|
||||||
return str != null && COMBINING_STRING.matcher(str).find();
|
return str != null && COMBINING_STRING.matcher(str).find();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates if the string contains only graphic characters (e.g. emojis)
|
||||||
|
*/
|
||||||
public static boolean isGraphic(String str) {
|
public static boolean isGraphic(String str) {
|
||||||
if (str == null || str.isEmpty()) {
|
if (str == null || str.isEmpty()) {
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -48,23 +47,51 @@ public class TextTools {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates Chinese text and punctuation.
|
||||||
|
*/
|
||||||
public static boolean isChinese(String str) {
|
public static boolean isChinese(String str) {
|
||||||
return str != null && IS_CHINESE.matcher(str).find();
|
return str != null && IS_CHINESE.matcher(str).find();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static boolean isHangul(String str) {
|
/**
|
||||||
return str != null && IS_HANGUL.matcher(str).find();
|
* Validates Japanese text and punctuation.
|
||||||
}
|
*/
|
||||||
|
|
||||||
|
|
||||||
public static boolean isJapanese(String str) {
|
public static boolean isJapanese(String str) {
|
||||||
return str != null && IS_JAPANESE.matcher(str).find();
|
return str != null && IS_JAPANESE.matcher(str).find();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static boolean isThai(String str) {
|
/**
|
||||||
return str != null && IS_THAI.matcher(str).find();
|
* Validates Chinese text only, but no punctuation.
|
||||||
|
*/
|
||||||
|
public static boolean isChineseText(String str) {
|
||||||
|
return str != null && IS_CHINESE_TEXT.matcher(str).find();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates Japanese text only, but no punctuation.
|
||||||
|
*/
|
||||||
|
public static boolean isJapaneseText(String str) {
|
||||||
|
return str != null && IS_JAPANESE_TEXT.matcher(str).find();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates Korean text only, but no punctuation.
|
||||||
|
*/
|
||||||
|
public static boolean isHangulText(String str) {
|
||||||
|
return str != null && IS_HANGUL_TEXT.matcher(str).find();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates Thai text only, but no punctuation.
|
||||||
|
*/
|
||||||
|
public static boolean isThaiText(String str) {
|
||||||
|
return str != null && IS_THAI_TEXT.matcher(str).find();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue