Android Get Country Emoji Flag Using Locale - android

I have seen that since Lollipop, Android has built in Emoji flags for different countries. Is it possible to use the devices locale to retrieve the Emoji flag for that country?
I wanted to insert the Emoji flag into a TextView which contains the user's location.

Emoji is a Unicode symbols. Based on the Unicode character table Emoji flags consist of 26 alphabetic Unicode characters (A-Z) intended to be used to encode ISO 3166-1 alpha-2 two-letter country codes (wiki).
That means it is possible to split two-letter country code and convert each A-Z letter to regional indicator symbol letter:
private String localeToEmoji(Locale locale) {
String countryCode = locale.getCountry();
int firstLetter = Character.codePointAt(countryCode, 0) - 0x41 + 0x1F1E6;
int secondLetter = Character.codePointAt(countryCode, 1) - 0x41 + 0x1F1E6;
return new String(Character.toChars(firstLetter)) + new String(Character.toChars(secondLetter));
}
Or in Kotlin, for example (assuming UTF-8):
val Locale.flagEmoji: String
get() {
val firstLetter = Character.codePointAt(country, 0) - 0x41 + 0x1F1E6
val secondLetter = Character.codePointAt(country, 1) - 0x41 + 0x1F1E6
return String(Character.toChars(firstLetter)) + String(Character.toChars(secondLetter))
}
Where 0x41 represents uppercase A letter and 0x1F1E6 is REGIONAL INDICATOR SYMBOL LETTER A in the Unicode table.
Note: This code example is simplified and doesn't have required checks related to country code, that could be not available inside the locale.

Based on this answer, I wrote a Kotlin version below using extension function.
I also added some checks to handle unknown country code.
/**
* This method is to change the country code like "us" into 🇺🇸
* Stolen from https://stackoverflow.com/a/35849652/75579
* 1. It first checks if the string consists of only 2 characters: ISO 3166-1 alpha-2 two-letter country codes (https://en.wikipedia.org/wiki/Regional_Indicator_Symbol).
* 2. It then checks if both characters are alphabet
* do nothing if it doesn't fulfil the 2 checks
* caveat: if you enter an invalid 2 letter country code, say "XX", it will pass the 2 checks, and it will return unknown result
*/
fun String.toFlagEmoji(): String {
// 1. It first checks if the string consists of only 2 characters: ISO 3166-1 alpha-2 two-letter country codes (https://en.wikipedia.org/wiki/Regional_Indicator_Symbol).
if (this.length != 2) {
return this
}
val countryCodeCaps = this.toUpperCase() // upper case is important because we are calculating offset
val firstLetter = Character.codePointAt(countryCodeCaps, 0) - 0x41 + 0x1F1E6
val secondLetter = Character.codePointAt(countryCodeCaps, 1) - 0x41 + 0x1F1E6
// 2. It then checks if both characters are alphabet
if (!countryCodeCaps[0].isLetter() || !countryCodeCaps[1].isLetter()) {
return this
}
return String(Character.toChars(firstLetter)) + String(Character.toChars(secondLetter))
}
Runnable Code Snippet
I also included a runnable Kotlin snippet using Kotlin Playground. In order to run the snippet you need to:
click "Show code snippet"
click "Run Code Snippet"
click the play button at the right top of the generated console
scroll to the bottom to see the result (it's hidden..)
<script src="https://unpkg.com/kotlin-playground#1.6.0/dist/playground.min.js" data-selector=".code"></script>
<div class="code" style="display:none;">
/**
* This method is to change the country code like "us" into 🇺🇸
* Stolen from https://stackoverflow.com/a/35849652/75579
* 1. It first checks if the string consists of only 2 characters: ISO 3166-1 alpha-2 two-letter country codes (https://en.wikipedia.org/wiki/Regional_Indicator_Symbol).
* 2. It then checks if both characters are alphabet
* do nothing if it doesn't fulfil the 2 checks
* caveat: if you enter an invalid 2 letter country code, say "XX", it will pass the 2 checks, and it will return unknown result
*/
fun String.toFlagEmoji(): String {
// 1. It first checks if the string consists of only 2 characters: ISO 3166-1 alpha-2 two-letter country codes (https://en.wikipedia.org/wiki/Regional_Indicator_Symbol).
if (this.length != 2) {
return this
}
val countryCodeCaps = this.toUpperCase() // upper case is important because we are calculating offset
val firstLetter = Character.codePointAt(countryCodeCaps, 0) - 0x41 + 0x1F1E6
val secondLetter = Character.codePointAt(countryCodeCaps, 1) - 0x41 + 0x1F1E6
// 2. It then checks if both characters are alphabet
if (!countryCodeCaps[0].isLetter() || !countryCodeCaps[1].isLetter()) {
return this
}
return String(Character.toChars(firstLetter)) + String(Character.toChars(secondLetter))
}
fun main(args: Array<String>){
println("us".toFlagEmoji())
println("AF".toFlagEmoji())
println("BR".toFlagEmoji())
println("MY".toFlagEmoji())
println("JP".toFlagEmoji())
}
</div>

When I first wrote this answer I somehow overlooked that I've only worked on Android via React Native!
Anyway, here's my JavaScript solution that works with or without ES6 support.
function countryCodeToFlagEmoji(country) {
return typeof String.fromCodePoint === "function"
? String.fromCodePoint(...[...country].map(c => c.charCodeAt() + 0x1f185))
: [...country]
.map(c => "\ud83c" + String.fromCharCode(0xdd85 + c.charCodeAt()))
.join("");
}
console.log(countryCodeToFlagEmoji("au"));
console.log(countryCodeToFlagEmoji("aubdusca"));
If you want to pass in the country codes as capital letters instead, just change the two offsets to 0x1f1a5 and 0xdda5.

You can get the country code very simple.
I want to talk about flag selection according to country code.
I wrote a class about it and it is very simple to use.
usage:
String countryWithFlag = CountryFlags.getCountryFlagByCountryCode("TR") + " " + "Türkiye";
Output : 🇹🇷 Türkiye
You can use it with Android TextView too :)
You can check out the class here
It works very well on Android 6 and above.

I am using this so easily.
Get the Unicode from here.
For Bangladesh flag it is U+1F1E7 U+1F1E9
Now,
{...
String flag = getEmojiByUnicode(0x1F1E7)+getEmojiByUnicode(0x1F1E9)+ " Bangladesh";
}
public String getEmojiByUnicode(int unicode){
return new String(Character.toChars(unicode));
}
It will show > (Bangladeshi flag) Bangladesh

I was looking for that too but I don't think it's possible yet.
Have a look here:
http://developer.android.com/reference/java/util/Locale.html
No mentioning about flags.
_
Alternately you can check the answer here:
Android Countries list with flags and availability of getting iso mobile codes
that might help you.

Related

String.format with English local but numbers are arabic

I am calculating priceAfterDsicount then place value in EditText(so user can modify it after App calculation)
Value retured from format is arabic numbers
this is code
private fun handleDiscount() {
val price = edPackagePrice.text.toString().toDoubleOrNull()
val discount = discount_percentage_edit_text.text.toString().toIntOrNull()
"handleDiscount before price$price discount$discount".log(mTag)
price?.let {
discount?.let {
val finalValue = String.format("%.1f", ValuesHelper.getPercentage(price, discount),Locale.US)
price_after_discount_edit_text.setText(finalValue)
"handleDiscount ook price$price discount$discount, final $finalValue".log(mTag)
}
}
if (discount == null) {
"handleDiscount $price , ${edPackagePrice.text}".log(mTag)
price_after_discount_edit_text.setText("")
price?.let { price_after_discount_edit_text.setText(price.toString()) }
}
"handleDiscount after price_after_discount_edit_text${price_after_discount_edit_text.text.toString()} ".log(mTag)
}
Output at Run
so what is problem?
NOTE
App language is arabic(user can change it from app).
I found other way to convert arabic number to english
Use Java.math.BigDecimal ,it will automatically construct English numeric equivalent to Arabic numeric equivalent , After you have English numeric equivalent do your calculation and when you want to update the UI after calculation use the device locale to show the end result to user in Arabic , BigDecimal only work with digits i.e. 0123. For special characters like , you have to do exception handling , we have .isDigit() method of Character class that you can leverage to iterate over whole input string and remove , before doing calculation,hope this helps.

How to detect #mentions in Kotlin using regex?

I need help in matching the #mentions words which itself contains some ids which will be used to redirect users to particular userId.
Here is my string:
val string = "Hello #[%user%]Akash(ef54321). Is #[%user%]Shubham(45321gg) there with you?"
I need parsed response == "Hello #Akash. Is #Shubham there with you?"
Also onClick of #Akash And #Shubham I need ids which are there in format (xxxxx).And #mentions should appear in grey background.Any help would be highly appreciated.Thanks,
I am using
val string = "Hello #[%user%]Akash(54321).Is #[%user%]Shubham(543215) there with you "
val matcher = Pattern.compile("^[#]\\w+|(?<=\\s)[#]\\w+").matcher(string)
while (matcher.find()) {
println("TAG"+matcher.group())
}
You may use
val string = "Hello #[%user%]Akash(ef54321). Is #[%user%]Shubham(45321gg) there with you?"
val rx = Regex("""#\[%user%](\w+)\((\w+)\)""")
val res = string.replace(rx, "#$1")
println(res) // => Hello #Akash. Is #Shubham there with yo?
val users =rx.findAll(string).map{it.groups[1]!!.value}.toList()
val ids =rx.findAll(string).map{it.groups[2]!!.value}.toList()
println(users) // => [Akash, Shubham]
println(ids) // => [ef54321, 45321gg]
See the Kotlin demo.
The #\[%user%](\w+)\((\w+)\) regex contains two capturing groups for users and for IDs. In the replacement method, you may refer to those values using $1 and $2 placeholders.
Pattern details
#\[%user%] - a #[%user%] literal string
(\w+) - Capturing group 1 (user, $1): one or more letters, digits or underscores
\( - a ( char
(\w+) - Capturing group 2 (ID, $2): one or more letters, digits or underscores
\) - a ) char.

Prevent numbers from changing according to the locale in android

When the user change the locale in device the numbers are also getting changed according to the selected locale. This is causing NumberFormatException while performing mathematical operations and app is getting crashed. The code snippet which is causing the crash is given below.
public static double ToDataUnitMB(double _dataBytes){
double dDataBytes;
dDataBytes = Double.parseDouble(getDecimalFormat().format(_dataBytes / 1048576));
return dDataBytes; }
This code snippet is causing NumberFormatException and the value in _dataBytes is shown as "७२.४१". Can anyone help me to prevent the number from changing when user change the locale.
Update
I am getting the value "७२.४१" after performing the below operation getDecimalFormat().format(_dataBytes / 1048576)
So while parsing to Double it is showing numberFormatException
Since you're starting with raw _dataBytes you have several options how to format number independent of the locale.
First Approach:
You can modify following snippet to your needs. It will give you the same output regardless of the user locale.
String patern = "###.##"; //your pattern as per need
Locale locale = new Locale("en", "US");
DecimalFormat decimalFormat = (DecimalFormat) NumberFormat.getNumberInstance(locale);
decimalFormat.applyPattern(patern);
double formatedDouble = Double.parseDouble(decimalFormat.format(_dataBytes/(1024*1024f)));
Keep in mind that this method also makes grouping and decimal separators to be fixed, so that comma and dot will alway be used as, respectively, grouping separator and decimal separator.
Second Approach:
If you do not strictly require Double you could generate formatted String with something similar to following method:
String generateFormatedFileSize(long _dataBytes) {
String formatedFileSize = "";
long bytes = _dataBytes;
short unit = 1024;
if (bytes < unit)
formatedFileSize = bytes + " B";
else {
int exp = (int) (Math.log(bytes) / Math.log(unit));
formatedFileSize = String.format("%.1f %sB", bytes / Math.pow(unit, exp), "KMGT".charAt(exp - 1));
}
return formatedFileSize;
}
This formatting will be sensitive to grouping separator and decimal separator, but otherwise insensitive to Locale.
For Local that uses "US" numbering format, this will give you following output:
12.5 KB
5.3 B
8.0 MB
And for Local using "European" numbering format:
12,5 KB
5,3 B
8,0 MB
Off course, these two methods are not exclusive and you could use some mix of these approaches at different parts of the App.

accepting acents in regex android

mates...
I am having troubles to pass through a regex accepting accents in android... All the things we have try like for java is not working properly, and android don't want our accented vocals ..
I have the following regex:
Pattern pattern = Pattern.compile("[a-zA-ZñÑáéíóúÁÉÍÓÚ]+");
Any tip of how to include ñ and accents vocals in android?
Thanks very much in advance...
Here is our validation function:
public static boolean validarNombres(String nameToValidate){
byte step = 1;
byte minWords = 2;
byte maxWords = 5;
boolean validName = false;
String[] aux;
Matcher matcher = null;
Pattern pattern = Pattern.compile("[\\p{L}\\p{M}]+");
aux = nameToValidate.split(" ");
//PASO 2: check that the name has from 2 to 5 words
if(aux.length >= minWords && aux.length <= maxWords){
step++;
matcher = pattern.matcher(nameToValidate);
}
//PASO 3: check that the name matches out regex
if(step==2 && matcher.matches()){
validName = true;
}
return validName;
}
EDIT: Think found the mistake... We are not including the blank space bettwen the first and second name ... It works fine when we check just a word, but not for the full name... now....
Whats the code to include a blank space on our regex?, please
Thanks very much
To validate a string consisting of 2 to 5 words separated with whitespace(s), you may use
public static boolean validarNombres(String nameToValidate) {
return nameToValidate.matches("[\\p{L}\\p{M}]+(?:\\s[\\p{L}\\p{M}]+){1,4}");
}
The regex is anchored by default when used with the .matches() method, no need adding ^ and $.
Pattern details:
[\\p{L}\\p{M}]+ - 1 or more letters or/and diacritics
(?:\\s[\\p{L}\\p{M}]+){1,4} - 1 to 4 (so, 2 to 5 in total) sequences of:
\\s - a single whitespace
[\\p{L}\\p{M}]+ - 1 or more letters or/and diacritics
See the regex demo.

Extract code country from phone number [libphonenumber]

I have a string like this : +33123456789 (french phone number). I want to extract the country code (+33) without knowing the country. For example, it should work if i have another phone from another country. I use the google library https://code.google.com/p/libphonenumber/.
If I know the country, it is cool I can find the country code :
PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance();
int countryCode = phoneUtil.getCountryCodeForRegion(locale.getCountry());
but I don't find a way to parse a string without to know the country.
Okay, so I've joined the google group of libphonenumber ( https://groups.google.com/forum/?hl=en&fromgroups#!forum/libphonenumber-discuss ) and I've asked a question.
I don't need to set the country in parameter if my phone number begins with "+". Here is an example :
PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance();
try {
// phone must begin with '+'
PhoneNumber numberProto = phoneUtil.parse(phone, "");
int countryCode = numberProto.getCountryCode();
} catch (NumberParseException e) {
System.err.println("NumberParseException was thrown: " + e.toString());
}
I have got kept a handy helper method to take care of this based on one answer posted above:
Imports:
import com.google.i18n.phonenumbers.NumberParseException
import com.google.i18n.phonenumbers.PhoneNumberUtil
Function:
fun parseCountryCode( phoneNumberStr: String?): String {
val phoneUtil = PhoneNumberUtil.getInstance()
return try {
// phone must begin with '+'
val numberProto = phoneUtil.parse(phoneNumberStr, "")
numberProto.countryCode.toString()
} catch (e: NumberParseException) {
""
}
}
In here you can save the phone number as international formatted phone number
internationalFormatPhoneNumber = phoneUtil.format(givenPhoneNumber, PhoneNumberFormat.INTERNATIONAL);
it return the phone number as
International format +94 71 560 4888
so now I have get country code as this
String countryCode = internationalFormatPhoneNumber.substring(0,internationalFormatPhoneNumber.indexOf('')).replace('+', ' ').trim();
Hope this will help you
Here is a solution to get the country based on an international phone number without using the Google library.
Let me explain first why it is so difficult to figure out the country. The country code of few countries is 1 digit, 2, 3 or 4 digits. That would be simple enough. But the country code 1 is not just used for US, but also for Canada and some smaller places:
1339 USA
1340 Virgin Islands (Caribbean Islands)
1341 USA
1342 not used
1343 Canada
Digits 2..4 decide, if it is US or Canada or ... There is no easy way to figure out the country, like the first xxx are Canada, the rest US.
For my code, I defined a class which holds information for ever digit:
public class DigitInfo {
public char Digit;
public Country? Country;
public DigitInfo?[]? Digits;
}
A first array holds the DigitInfos for the first digit in the number. The second digit is used as an index into DigitInfo.Digits. One travels down that Digits chain, until Digits is empty. If Country is defined (i.e. not null) that value gets returned, otherwise any Country defined earlier gets returned:
country code 1: byPhone[1].Country is US
country code 1236: byPhone[1].Digits[2].Digits[3].Digits[6].Country is Canada
country code 1235: byPhone[1].Digits[2].Digits[3].Digits[5].Country is null. Since
byPhone[1].Country is US, also 1235 is US, because no other
country was found in the later digits
Here is the method which returns the country based on the phone number:
/// <summary>
/// Returns the Country based on an international dialing code.
/// </summary>
public static Country? GetCountry(ReadOnlySpan<char> phoneNumber) {
if (phoneNumber.Length==0) return null;
var isFirstDigit = true;
DigitInfo? digitInfo = null;
Country? country = null;
foreach (var digitChar in phoneNumber) {
var digitIndex = digitChar - '0';
if (isFirstDigit) {
isFirstDigit = false;
digitInfo = ByPhone[digitIndex];
} else {
if (digitInfo!.Digits is null) return country;
digitInfo = digitInfo.Digits[digitIndex];
}
if (digitInfo is null) return country;
country = digitInfo.Country??country;
}
return country;
}
The rest of the code (digitInfos for every country of the world, test code, ...) is too big to be posted here, but it can be found on Github:
https://github.com/PeterHuberSg/WpfWindowsLib/blob/master/WpfWindowsHelperLib/CountryCode.cs
The code is part of a WPF TextBox and the library contains also other controls for email addresses, etc. A more detailed description is on CodeProject: International Phone Number Validation Explained in Detail
Change 23.1.23: I moved CountryCode.cs to WpfWindowsHelperLib, which doesn't have any WPF dependencies, despite it's name.
Use a try catch block like below:
try {
const phoneNumber = this.phoneUtil.parseAndKeepRawInput(value, this.countryCode);
}catch(e){}
If the string containing the phone number will always start this way (+33 or another country code) you should use regex to parse and get the country code and then use the library to get the country associated to the number.
Here's a an answer how to find country calling code without using third-party libraries (as real developer does):
Get list of all available country codes, Wikipedia can help here:
https://en.wikipedia.org/wiki/List_of_country_calling_codes
Parse data in a tree structure where each digit is a branch.
Traverse your tree digit by digit until you are at the last branch - that's your country code.

Categories

Resources