I am using Android Text to Speech engine for reading some text and it's working. But my text contains numbers and I want the numbers to be read digit by digit.
I couldn't find anything in the documentation, but I am still hoping someone knows how I can do that.
The API does not allow you to specify how the text should be read so your code has to modify the text input so that it reads the individual numbers.
I suggest adding a space in between each number. That should cause the TextToSpeech to read the individual numbers.
If you need some code to help you detect numbers use this:
private boolean isNumber(String word)
{
boolean isNumber = false;
try
{
Integer.parseInt(word);
isNumber = true;
} catch (NumberFormatException e)
{
isNumber = false;
}
return isNumber;
}
The accepted answer has a minor flaw . If the number has '0' as one of it's digits , it would be read as alphabet 'o' instead of Zero . I would suggest the following solution .
String number = "1230";
for(int i = 0 ; i < number.size(); i++) {
/* refer Speech API , Don't use QUEUE_FLUSH as it results in flushing
some characters in this case */
engine.speak(Character.toString(number.charAt(i)),QUEUE_ADD,null);
}
/* refer Speech API , Don't use QUEUE_FLUSH as it results in flushing
some characters in this case */
for(int i = 0 ; i < number.size(); i++) {
engine.speak(Character.toString(number.charAt(i)),QUEUE_ADD,null);
}
Related
I have a big paragraph which may have numbers, email addresses and links. So I have to set setAutoLinkMask(Linkify.PHONE_NUMBERS | Linkify.EMAIL_ADDRESSES | Linkify.WEB_URLS) for my textview.
The content may contain digits of varying numbers. I want to set numbers having atleast 8 digits as phone number links.(For Eg : 12345678)
Is it possible to set minimum length for Linkify.PHONE_NUMBERS ?
Is there anyway to achieve this?
In case you can use Linkify.MatchFilter to specify minimum length or your some other requirements. There is not any direct way provided by Android.
Also somewhere in this SO post found some good examples.
use below pattern :
SpannableString buffer = new SpannableString(text);
Pattern pattern = Pattern.compile("^[0-9]\d{7,9}$");
Linkify.addLinks(buffer , pattern,"");
Yes, its possible. I researched this phenomenon :-)
To set the minimum length for a phone number, use this code:
private final Linkify.MatchFilter matchFilterForPhone = new Linkify.MatchFilter() {
#Override
public boolean acceptMatch(CharSequence s, int start, int end) {
int digitCount = 0;
for (int i = start; i < end; i++) {
if (Character.isDigit(s.charAt(i))) {
digitCount++;
if (digitCount >= 6) { // HERE: number 6 is minimum
return true;
}
}
}
return false;
}
};
To properly format and link phone numbers, use:
final SpannableString s = new SpannableString(myTekst);
Linkify.addLinks(s, android.util.Patterns.PHONE, "tel:", matchFilterForPhone, Linkify.sPhoneNumberTransformFilter);
Now place the formatted s in your TextView, and call:
findViewById(R.id.message).setLinkTextColor(Color.BLUE);
findViewById(R.id.message).setMovementMethod(LinkMovementMethod.getInstance());
That's all. Thanks for vote.
I'm working on an Android app, and I do not want people to use emoji in the input.
How can I remove emoji characters from a string?
Emojis can be found in the following ranges (source) :
U+2190 to U+21FF
U+2600 to U+26FF
U+2700 to U+27BF
U+3000 to U+303F
U+1F300 to U+1F64F
U+1F680 to U+1F6FF
You can use this line in your script to filter them all at once:
text.replace("/[\u2190-\u21FF]|[\u2600-\u26FF]|[\u2700-\u27BF]|[\u3000-\u303F]|[\u1F300-\u1F64F]|[\u1F680-\u1F6FF]/g", "");
Latest emoji data can be found here:
http://unicode.org/Public/emoji/
There is a folder named with emoji version.
As app developers a good idea is to use latest version available.
When You look inside a folder, You'll see text files in it.
You should check emoji-data.txt. It contains all standard emoji codes.
There are a lot of small symbol code ranges for emoji.
Best support will be to check all these in Your app.
Some people ask why there are 5 digit codes when we can only specify 4 after \u.
Well these are codes made from surrogate pairs. Usually 2 symbols are used to encode one emoji.
For example, we have a string.
String s = ...;
UTF-16 representation
byte[] utf16 = s.getBytes("UTF-16BE");
Iterate over UTF-16
for(int i = 0; i < utf16.length; i += 2) {
Get one char
char c = (char)((char)(utf16[i] & 0xff) << 8 | (char)(utf16[i + 1] & 0xff));
Now check for surrogate pairs. Emoji are located on the first plane, so check first part of pair in range 0xd800..0xd83f.
if(c >= 0xd800 && c <= 0xd83f) {
high = c;
continue;
}
For second part of surrogate pair range is 0xdc00..0xdfff. And we can now convert a pair to one 5 digit code.
else if(c >= 0xdc00 && c <= 0xdfff) {
low = c;
long unicode = (((long)high - 0xd800) * 0x400) + ((long)low - 0xdc00) + 0x10000;
}
All other symbols are not pairs so process them as is.
else {
long unicode = c;
}
Now use data from emoji-data.txt to check if it's emoji.
If it is, then skip it. If not then copy bytes to output byte array.
Finally byte array is converted to String by
String out = new String(outarray, Charset.forName("UTF-16BE"));
For those using Kotlin, Char.isSurrogate can help as well. Find and remove the indexes that are true from that.
Here is what I use to remove emojis. Note: This only works on API 24 and forwards
public String remove_Emojis_For_Devices_API_24_Onwards(String name)
{
// we will store all the non emoji characters in this array list
ArrayList<Character> nonEmoji = new ArrayList<>();
// this is where we will store the reasembled name
String newName = "";
//Character.UnicodeScript.of () was not added till API 24 so this is a 24 up solution
if (Build.VERSION.SDK_INT > 23) {
/* we are going to cycle through the word checking each character
to find its unicode script to compare it against known alphabets*/
for (int i = 0; i < name.length(); i++) {
// currently emojis don't have a devoted unicode script so they return UNKNOWN
if (!(Character.UnicodeScript.of(name.charAt(i)) + "").equals("UNKNOWN")) {
nonEmoji.add(name.charAt(i));//its not an emoji so we add it
}
}
// we then cycle through rebuilding the string
for (int i = 0; i < nonEmoji.size(); i++) {
newName += nonEmoji.get(i);
}
}
return newName;
}
so if we pass in a string:
remove_Emojis_For_Devices_API_24_Onwards("๐ test ๐ Indic:เคข Japanese:ใช ๐ Korean:ใ
");
it returns: test Indic:เคข Japanese:ใช Korean:ใ
Emoji placement or count doesn't matter
I have written a calculator type app. My mates found that entering single decimal points only into the editText's makes the app crash. Decimal numbers and integers work fine, but I get a number format exception when .'s are entered.
I want to check if a single . has been placed in an editText, in order for me to display a toast telling the user to stop trying to crash the app.
My issue is that a . doesn't have a numerical value...
You can wrap it in a try/catch which should be done anyway when parsing text. So something like
try
{
int someInt = Integer.parseInt(et.getText().toString());
// other code
}
catch (NumberFormatException e)
{
// notify user with Toast, alert, etc...
}
This way it will protect against any number format exception and will make the code more reusable later on.
You can treat .1 as 0.1 by the following.
String text = et.getText().toString();
int len = text.length();
// Do noting if edit text just contains a "." without numbers
if(len==0 || (len==1 && text.charAt(0).equals(".")))
return;
if(text.charAt(0).equals(".") && text.length() > 1) {
text = "0" + text;
}
// Do your parsing and calculations
I've seen many people do similar to this in order to get the last word of a String:
String test = "This is a sentence";
String lastWord = test.substring(test.lastIndexOf(" ")+1);
I would like to do similar but get the last few words after the last int, it can't be hard coded as the number could be anything and the amount of words after the last int could also be unlimited. I'm wondering whether there is a simple way to do this as I want to avoid using Patterns and Matchers again due to using them earlier on in this method to receive a similar effect.
Thanks in advance.
I would like to get the last few words after the last int.... as the number could be anything and the amount of words after the last int could also be unlimited.
Here's a possible suggestion. Using Array#split
String str = "This is 1 and 2 and 3 some more words .... foo bar baz";
String[] parts = str.split("\\d+(?!.*\\d)\\s+");
And now parts[1] holds all words after the last number in the string.
some more words .... foo bar baz
What about this one:
String test = "a string with a large number 1312398741 and some words";
String[] parts = test.split();
for (int i = 1; i < parts.length; i++)
{
try
{
Integer.parseInt(parts[i])
}
catch (Exception e)
{
// this part is not a number, so lets go on...
continue;
}
// when parsing succeeds, the number was reached and continue has
// not been called. Everything behind 'i' is what you are looking for
// DO YOUR STUFF with parts[i+1] to parts[parts.length] here
}
I have a character and I want to convert it into KeyEvent KeyCode constraints http://developer.android.com/reference/android/view/KeyEvent.html#KEYCODE_0
Like if I have a character '0' I wan to convert into
Key code constant: '0' key.
Constant Value: 7 (0x00000007)
as specified in the KeyEvent page. What can be a best method for doing this? Is there any predefined function to do it?
Here is a solution I use to put chars in a webview:
char[] szRes = szStringText.toCharArray(); // Convert String to Char array
KeyCharacterMap CharMap;
if(Build.VERSION.SDK_INT >= 11) // My soft runs until API 5
CharMap = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD);
else
CharMap = KeyCharacterMap.load(KeyCharacterMap.ALPHA);
KeyEvent[] events = CharMap.getEvents(szRes);
for(int i=0; i<events.length; i++)
MainWebView.dispatchKeyEvent(events[i]); // MainWebView is webview
I'm still new to Java/Android, so my answer may not work out of the box, but you may still get the idea.
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
...
public class Sample {
...
public boolean convertStringToKeyCode(String text) {
KeyCharacterMap mKeyCharacterMap =
KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD);
KeyEvent[] events = mKeyCharacterMap.getEvents(text.toCharArray());
for (KeyEvent event2 : events) {
// We get key events for both UP and DOWN actions,
// so we may just need one.
if (event2.getAction() == 0) {
int keycode = event2.getKeyCode();
// Do some work
}
}
}
I got the idea when I was reading the code of sendText method in uiautomator framework source code:
Very rude solution but works for most characters.
Remember to do an uppercase if your text contains lowercase letters, you can add META_SHIFT_ON in that case if you then send a KeyEvent
for (int i = 0; i < text.length(); i++) {
final char ch = text.charAt(i);
try {
dispatch(KeyEvent.class.getField("KEYCODE_" + ch).getInt(null));
} catch (Exception e) {
Log.e(_TAG, "Unknown keycode for " + ch);
}
}
No, you cannot read a character "0" from the input and use a magical function to transform that to KeyEvent.KEYCODE_0 ... If you do, you will have to write a parser that switches on the read letter and return these values yourself.
For all I know, before reading the character you should've captured the thing in the onKey(). Depending on the number of keys you need to handle this way, a virtual android keyboard might be your only option, if this boilerplate code doesn't do the trick
switch(keyPress)
{
case '0': return KeyEvent.KEYCODE_0;
case '1': return ...
//...
case 'Z': return KeyEvent.KEYCODE_Z;
}