I have a database with millions of phone numbers with free-for-all formatting. Ie, the UI does not enforce any constraints and the users are typing in whatever they want.
What I'm looking for is a Java API that can make a best-effort to convert these into a consistent format. Ideally, the API would take the free text value and a country code and produce a valid international phone number or throw an exception.
For example, a phone number in the system might look like any of the following:
(555) 478-1123
555-478-1123
555.478.1123
5554781123
Given the country of US, the API would produce the value "+1 (555) 478-1123" for all these. The exact format does not matter, as long as it's consistent.
There are also numbers in the system without area codes, such as "478-1123". In that case, I would expect a NoAreaCodeException, or something similar.
There could also be data such as "abc", which should also throw exceptions.
Of course, there are countless variations of the examples I have posted, as well as the enormous complication of international phone numbers, which have quite complicated validation rules. This is why I would not consider rolling my own.
Has anyone seen such an API?
You could write your own (for US phone # format):
Strip any non-numeric characters from the string
Check that the remaining string is ten characters long
Put parentheses around the first three characters and a dash between the sixth and seventh character.
Prepend "+1 " to the string
Update:
Google recently released libphonenumber for parsing, formatting, storing and validating international phone numbers.
You could try this Java phone number formatting library https://github.com/googlei18n/libphonenumber
It has data for hundreds of countries and formats.
Simple regex parser
/**
* #param pPhoneNumber
* #return true if the phone number is correct
*/
private boolean isPhoneNumberCorrect(String pPhoneNumber) {
Pattern pattern = Pattern
.compile("((\\+[1-9]{3,4}|0[1-9]{4}|00[1-9]{3})\\-?)?\\d{8,20}");
Matcher matcher = pattern.matcher(pPhoneNumber);
if (matcher.matches()) return true;
return false;
}
Format
I made this according to my needs, and it accepts numbers:
CountryCode-Number
Number
Country Codes:
They may have a: +, or either one or two zeros.
Then, it may be followed by a -.
Accepts:
+456
00456
+1234
01234
All above may or may not followed by a -
Rejects:
0456
it should be:
00456 or+456 or04444
Number
A simple number with 8-20 digits.
Accepts:
00456-12345678
+457-12345678
+45712345678
0045712345678
99999999
Extend it?
Feel free, so you may include support for . or '(' separators. Just make sure you escape them, e.g. for ( use \(.
I don't know of such an API but it looks like could be done by using regular expressions. Probably you can't convert all numbers to a valid format but most of them.
The recent versions of http://code.google.com/p/libphonenumber/ have added metadata for many new countries and added a lot more detail for some of the countries previously listed.
The current source code version is r74 and the .jar file is at version 2.6. Previous .jar files were compiled for Java 1.6, but as of libphonenumber version 2.5.1 onwards they are now compiled for Java 1.5 and above.
Don't forget there is also a direct port of the code to JavaScript. It can be found in the source code tree at http://code.google.com/p/libphonenumber/source/browse/#svn%2Ftrunk%2Fjavascript
Bug reports are welcome. Updates to metadata are actively encouraged, as even the official government-published area code lists for many countries are either incomplete or out of date.
Don't re-invent the wheel; use an API, e.g. http://libphonenumber.googlecode.com/
This API gives you nice formatting, too.
Example:
String number = "(555) 478-1123";
PhoneNumberUtil phoneNumberUtil = PhoneNumberUtil.getInstance();
try {
Phonenumber.PhoneNumber phoneNumber = phoneNumberUtil.parse(number, Locale.US.getCountry());
} catch (NumberParseException e) {
// error handling
}
You could even use the phoneNumber object to nicely format it a valid phone number before saving it to the DB or whatever.
For French number which look like "01 44 55 66 77", we can use the following logic.
DecimalFormatSymbols dfs = new DecimalFormatSymbols();
dfs.setGroupingSeparator(' '); // sometimes '.' is used
DecimalFormat decfmt = new DecimalFormat("0,0", dfs); // enable grouping
decfmt.setMinimumIntegerDigits(10); // we always have 10 digits
decfmt.setGroupingSize(2); // necessary in order to group digits by 2 orders
System.out.println(decfmt.format(144556677)); // outputs "01 44 55 66 77"
Once this could be done, with google's phone number API the others mentioned, we can parse these sequences easily and reformat them into other forms such as "+33 1 44 55 66 77" like the following:
Iterable<PhoneNumberMatch> numbers = PhoneNumberUtil.getInstance().findNumbers(textWithPhoneNums, "FR");
for(Iterator<PhoneNumberMatch> iterator = numbers.iterator(); iterator.hasNext(); ){
PhoneNumberMatch pnm = iterator.next();
PhoneNumber number = pnm.number();
System.out.println(PhoneNumberUtil.getInstance().formatOutOfCountryCallingNumber(number, null));
}
I don't think there is a way of recognizing the lack of an area code unless your numbers are all from one country (presumably the USA), as each country has its own rules for things like area codes.
I'd start looking for detailed information here, here, and here - if there are APIs to handle it (in Java or otherwise), they might be linked to there as well.
There are commercial programs that format and validate international telephone numbers, like this one which even checks for valid area codes in some countries. For North America, the NANPA provides some resources for validating area codes.
The best i found was javax.telephony, to be found here: http://java.sun.com/products/javaphone/
It has an Address class, but sadly that class did not solve your problem :(
Well, maybe you can find a solution by digging deeper into it.
Apart of that, my first idea was to use regex. However, that seems to be a kind of bad solution to this specific problem.
My own needs were very simple. I just needed to take a 7 or 10-digit number and put separators (a dash, period, some string of characters, etc.) between the area code, exchange, and exchange number. Any value passed into the method that is not all digits or is not a length of 7 or 10 is simply returned. A null value returns an empty string and a null value for the separator is treated like an empty string. My code:
import java.util.regex.Matcher;
import java.util.regex.Pattern;
// ...
private String formatPhoneNumber(String phnumber, String separator) {
phnumber = (phnumber == null) ? "" : phnumber;
if ((phnumber.length() != 7) && (phnumber.length() != 10)) { return phnumber; }
// If we get here, 'phnumber' is for sure either 7 or 10 chars long
separator = (separator == null) ? "" : separator;
Pattern p = Pattern.compile("([0-9]*)");
Matcher m = p.matcher(phnumber);
if (m.matches()) {
if (phnumber.length() == 7) {
return phnumber.substring(0, 3) + separator + phnumber.substring(4);
} else {
return phnumber.substring(0, 3) + separator + phnumber.substring(3, 6)
+ separator + phnumber.substring(6);
}
// If we get here, it means 1 or more of the chars in 'phnumber'
// is not a digit and so 'phnumber' is returned just as passed in.
return phnumber;
}
I have created a Helper class using libphonenumber, But it is still on possibilities i.e (users mostly saves the local numbers in local contacts as local format) I mean without country code since it is local number but will save the International numbers with country code. and this helper works for both of these scenario's if the number is in global format it will simply keep it as it is while converts the local numbers to internal format. Below is the Code and Usage
class PhoneNumberHelper {
companion object {
fun correctNumber(number: String, context: Context): String? {
val code = StorageAdapter.get(context).userCountryCode
return validateNumber(number, code)
}
private fun validateNumber(number: String, mUserCountryCode: Int): String? {
return Utils.formatNumber(Utils.removeDelimetersFromNumber(number), mUserCountryCode)
}
fun formatNumber(destinationNumber: String, countryCode: Int): String? {
try {
val phoneUtil = PhoneNumberUtil.getInstance()
val regionCode = phoneUtil.getRegionCodeForCountryCode(countryCode)
var formattedNumber = formatNumber(destinationNumber, regionCode)
if (TextUtils.isEmpty(formattedNumber)) {
formattedNumber = destinationNumber
}
return formattedNumber
} catch (exp: Exception) {
Log.e("formatNumber", exp.toString())
}
return destinationNumber
}
fun formatNumber(destinationNumber: String, regionCode: String): String? {
if (TextUtils.isEmpty(regionCode)) {
return null
}
var number: String? = null
try {
val phoneUtil = PhoneNumberUtil.getInstance()
val phoneNumber = phoneUtil.parse(destinationNumber, regionCode)
if (phoneUtil.isValidNumber(phoneNumber)) {
/*
* E164 format is as per international format but no
* formatting applied e.g. no spaces in between
*/
number = phoneUtil.format(phoneNumber, PhoneNumberUtil.PhoneNumberFormat.E164)
number = number!!.replace("+", "00")
}
} catch (e: Exception) {
// number would be returned as null if it catches here
}
return number
}
}
}
Here Is how You will use it:
var globalnumber = PhoneNumberHelper.correctNumber(contact.mobile, context)
Clarification:
val code = StorageAdapter.get(context).userCountryCode
This is the Country code you should Store at during Signup. e.g. 0044 or +44
Don't forget to Include Dependency for libphone :
implementation 'com.googlecode.libphonenumber:libphonenumber:8.8.0'
Related
I want to make this so that short inputs can still be detected, such as "Londo" and "Lon", but want to keep it small and use it without basically copying and pasting the code, any tips? thank you.
if (Menu.answer1.equals("London"))
{
if (location.equals("London")) {
System.out.print(location + " ");
System.out.print(date + " ");
System.out.print(degrees + "C ");
System.out.print(wind + "MPH ");
System.out.print(winddirection + " ");
System.out.print(weather + " ");
System.out.println("");
}
You can use startsWith()
String city = "London";
if (city.startsWith("Lon")) {
// do something
}
Also if you need to check some substring, you can use contains method:
Menu.answer1 = "London";
Menu.answer1.contains("ondo"); // true
If you want to check against a fixed set of alternatives, you may use a list of valid inputs using contains:
List<String> londonNames = Arrays.asList("London", "Londo", "Lon");
if (londonNames.contains(Menu.answer1)) {
...
}
You can use (case-insensitive) regex to do the same, e.g.:
(?)Lon[a-z]{0,3} where
(?) = case insensitivity
Lon = Initial 3 characters
[a-z]{0,3} = any number of alphabets between 0 and 3
Here's an example:
String regex = "(?)Lon[a-z]{0,3}";
System.out.println("London".matches(regex));
System.out.println("Lond".matches(regex));
System.out.println("Lon".matches(regex));
If the underlying problem is that the user can enter one of several names, and you want to allow abbreviations, then a fairly standard approach is to have a table of acceptable names.
Given the user input, loop through the table testing "does the table entry start with the string typed by the user?" (like one of the previous answers here). If yes, then you have a potential match.
Keep looking. If you get a second match then the user input was ambiguous and should be rejected.
As a bonus, you can collect all names that match, and then use them in an error message. ("Pick one of London, Lonfoo, Lonbar").
This approach has the advantage (compared to a long chain of if-then-else logic) of not requiring you to write more code when all you want to do is have more data.
It automatically allows the shortest unique abbreviation, and will adjust when a once-unique abbreviation is no longer unique because of newly-added names.
I want to compare a string portion (i.e. character) against a Chinese character. I assume due to the Unicode encoding it counts as two characters, so I'm looping through the string with increments of two. Now I ran into a roadblock where I'm trying to detect the '兒' character, but equals() doesn't match it, so what am I missing ? This is the code snippet:
for (int CharIndex = 0; CharIndex < tmpChar.length(); CharIndex=CharIndex+2) {
// Account for 'r' like in dianr/huir
if (tmpChar.substring(CharIndex,CharIndex+2).equals("兒")) {
Also, feel free to suggest a more elegant way to parse this ...
[UPDATE] Some pics from the debugger, showing that it doesn't match, even though it should. I pasted the Chinese character from the spreadsheet I use as input, so I don't think it's a copy and paste issue (unless the unicode gets lost along the way)
oh, dang, apparently it does not work simply copy and pasting:
Use CharSequence.codePoints(), which returns a stream of the codepoints, rather than having to deal with chars:
tmpChar.codePoints().forEach(c -> {
if (c == '兒') {
// ...
}
});
(Of course, you could have used tmpChar.codePoints().filter(c -> c == '兒').forEach(c -> { /* ... */ })).
Either characters, accepting 兒 as substring.
String s = ...;
if (s.contains("兒")) { ... }
int position = s.indexOf("兒");
if (position != -1) {
int position2 = position + "兒".length();
s = s.substring(0, position) + "*" + s.substring(position2);
}
if (s.startsWith("兒", i)) {
// At position i there is a 兒.
}
Or code points where it would be one code point. As that is not really easier, variable substring seem fine.
if (tmpChar.substring(CharIndex,CharIndex+2).equals("兒")) {
Is your problem. 兒 is only one UTF-16 character. Many Chinese characters can be represented in UTF-16 in one code unit; Java uses UTF-16. However, other characters are two code units.
There are a variety of APIs on the String class for coping.
As offered in another answer, obtaining the IntStream from codepoints allows you to get a 32-bit code point for each character. You can compare that to the code point value for the character you are looking for.
Or, you can use the ICU4J library with a richer set of facilities for all of this.
i need to create a String with a country flag unicode emoji..I did this:
StringBuffer sb = new StringBuffer();
sb.append(StringEscapeUtils.unescapeJava("\\u1F1EB"));
sb.append(StringEscapeUtils.unescapeJava("\\u1F1F7"));
Expecting one country flag but i havent..How can i get a unicode country flag emoji in String with the unicodes characters?
The problem is, that the "\uXXXX" notation is for 4 hexadecimal digits, forming a 16 bit char.
You have Unicode code points above the 16 bit range, both U+F1EB and U+1F1F7. This will be represented with two chars, a so called surrogate pair.
You can either use the codepoints to create a string:
int[] codepoints = {0x1F1EB, 0x1F1F7};
String s = new String(codepoints, 0, codepoints.length);
Or use the surrogate pairs, derivable like this:
System.out.print("\"");
for (char ch : s.toCharArray()) {
System.out.printf("\\u%04X", (int)ch);
}
System.out.println("\"");
Giving
"\uD83C\uDDEB\uD83C\uDDF7"
Response to the comment: How to Decode
"\uD83C\uDDEB" are two surrogate 16 bit chars representing U+1F1EB and "\uD83C\uDDF7" is the surrogate pair for U+1F1F7.
private static final int CP_REGIONAL_INDICATOR = 0x1F1E7; // A-Z flag codes.
/**
* Get the flag codes of two (or one) regional indicator symbols.
* #param s string starting with 1 or 2 regional indicator symbols.
* #return one or two ASCII letters for the flag, or null.
*/
public static String regionalIndicator(String s) {
int cp0 = regionalIndicatorCodePoint(s);
if (cp0 == -1) {
return null;
}
StringBuilder sb = new StringBuilder();
sb.append((char)(cp0 - CP_REGIONAL_INDICATOR + 'A'));
int n0 = Character.charCount(cp0);
int cp1 = regionalIndicatorCodePoint(s.substring(n0));
if (cp1 != -1) {
sb.append((char)(cp1 - CP_REGIONAL_INDICATOR + 'A'));
}
return sb.toString();
}
private static int regionalIndicatorCodePoint(String s) {
if (s.isEmpty()) {
return -1;
}
int cp0 = s.codePointAt(0);
return CP_REGIONAL_INDICATOR > cp0 || cp0 >= CP_REGIONAL_INDICATOR + 26 ? -1 : cp0;
}
System.out.println("Flag: " + regionalIndicator("\uD83C\uDDEB\uD83C\uDDF7"));
Flag: EQ
You should be able to do that simply using toChars from java.lang.Character.
This works for me:
StringBuffer sb = new StringBuffer();
sb.append(Character.toChars(127467));
sb.append(Character.toChars(127479));
System.out.println(sb);
prints 🇫🇷, which the client can chose to display like a french flag, or in other ways.
If you want to use emojis often, it could be good to use a library that would handle that unicode stuff for you: emoji-java
You would just add the maven dependency:
<dependency>
<groupId>com.vdurmont</groupId>
<artifactId>emoji-java</artifactId>
<version>1.0.0</version>
</dependency>
And call the EmojiManager:
Emoji emoji = EmojiManager.getForAlias("fr");
System.out.println("HEY: " + emoji.getUnicode());
The entire list of supported emojis is here.
I suppose you want to achieve something like this
Let me give you 2 example of unicodes for country flags:
for ROMANIA ---> \uD83C\uDDF7\uD83C\uDDF4
for AMERICA ---> \uD83C\uDDFA\uD83C\uDDF8
You can get this and other country flags unicodes from this site Emoji Unicodes
Once you enter the site, you will see a table with a lot of emoji. Select the tab with FLAGS from that table (is easy to find it) then will appear all the country flags. You need to select one flag from the list, any flag you want... but only ONE. After that will appear a text code in the message box...that is not important. Important is that you have to look in the right of the site where will appear flag and country name of your selected flag. CLICK on that, and on the page that will open you need to find the TABLE named Emoji Character Encoding Data. Scroll until the last part of table where sais: C/C++/Java Src .. there you will find the correct unicode flag. Attention, always select the unicode that is long like that, some times if you are not carefull you can select a simple unicode, not long like that. So, keep that in mind.
Indications image 1
Indication image 2
In the end i will post a sample code from an Android app of mine that will work on java the same way.
ArrayList<String> listLanguages = new ArrayList<>();
listLanguages.add("\uD83C\uDDFA\uD83C\uDDF8 " + getString(R.string.English));
listLanguages.add("\uD83C\uDDF7\uD83C\uDDF4 " + getString(R.string.Romanian));
Another simple custom example:
String flagCountryName = "\uD83C\uDDEF\uD83C\uDDF2 Jamaica";
You can use this variable where you need it. This will show you the flag of Jamaica in front of the text.
This is all, if you did not understand something just ask.
Look at Creating Unicode character from its number
Could not get my machine to print the Unicode you have there, but for other values it works.
Wrote a method which takes in a String and checks to see the follow conditions:
If String is "quit", it will terminate the program.
If the String is any value other than an integer, it should return "Invalid input ".
Any negative integers and also 0 should return "Invalid input".
However, when I passed in 10, it returned as "Invalid input"?
Please advise:
public static String validate(String input) {
Pattern pattern = Pattern.compile(".*[^1-9].*");
StringBuilder results = new StringBuilder();
if (input.equals("quit")) {
System.exit(1);
} else if (!pattern.matcher(input).matches() == false) {
results.append("Invalid input ");
results.append("'");
results.append(input);
results.append("'");
}
return results.toString();
}
What's wrong with what I am doing?
You should write a pattern of what you expect instead of what you're not.
As describe what you want is always simpler that describe the rest of it.
So you expect :
Pattern acceptPattern = Pattern.compile("[1-9][0-9]*");
You may consider make you conditional expression simpler and correct by not using both ! and == false at the same time:
Which will make :
if (!acceptPattern .matcher(input).matches()) {//Invalid input code}
or
if (acceptPattern .matcher(input).matches() == false) {//Invalid input code}
note :
You write if(!A == false) => if(A == true) => if(A) but which was the inverse
It looks like you want to match one or more digits, where the first one is not a zero.
[1-9]\d*
If you want to force it to be the entire string, you can add anchors, like this:
^[1-9]\d*$
Your regex string doesn't allow for the presence of a zero (not just a lone zero).
That is, the string ".*[^1-9].*" is looking for "any number of characters, something that isn't 1-9, and any number of characters". When it finds the zero, it gives you your incorrect result.
Check out What is the regex for "Any positive integer, excluding 0" for how to change this.
Probably the most helpful solution on that page is the regex [0-9]*[1-9][0-9]* (for a valid integer). This allows for leading zeros and/or internal zeros, both of which could be present in a valid integer. In using Matcher#matches you also ensure that this regex matches the whole input, not just part of it (without the need to add in beginning and end anchors -- ^$).
Also, the line else if (!pattern.matcher(input).matches() == false) could be made a lot more clear.... maybe try else if (pattern.matcher(input).matches()) instead?
I have a database with millions of phone numbers with free-for-all formatting. Ie, the UI does not enforce any constraints and the users are typing in whatever they want.
What I'm looking for is a Java API that can make a best-effort to convert these into a consistent format. Ideally, the API would take the free text value and a country code and produce a valid international phone number or throw an exception.
For example, a phone number in the system might look like any of the following:
(555) 478-1123
555-478-1123
555.478.1123
5554781123
Given the country of US, the API would produce the value "+1 (555) 478-1123" for all these. The exact format does not matter, as long as it's consistent.
There are also numbers in the system without area codes, such as "478-1123". In that case, I would expect a NoAreaCodeException, or something similar.
There could also be data such as "abc", which should also throw exceptions.
Of course, there are countless variations of the examples I have posted, as well as the enormous complication of international phone numbers, which have quite complicated validation rules. This is why I would not consider rolling my own.
Has anyone seen such an API?
You could write your own (for US phone # format):
Strip any non-numeric characters from the string
Check that the remaining string is ten characters long
Put parentheses around the first three characters and a dash between the sixth and seventh character.
Prepend "+1 " to the string
Update:
Google recently released libphonenumber for parsing, formatting, storing and validating international phone numbers.
You could try this Java phone number formatting library https://github.com/googlei18n/libphonenumber
It has data for hundreds of countries and formats.
Simple regex parser
/**
* #param pPhoneNumber
* #return true if the phone number is correct
*/
private boolean isPhoneNumberCorrect(String pPhoneNumber) {
Pattern pattern = Pattern
.compile("((\\+[1-9]{3,4}|0[1-9]{4}|00[1-9]{3})\\-?)?\\d{8,20}");
Matcher matcher = pattern.matcher(pPhoneNumber);
if (matcher.matches()) return true;
return false;
}
Format
I made this according to my needs, and it accepts numbers:
CountryCode-Number
Number
Country Codes:
They may have a: +, or either one or two zeros.
Then, it may be followed by a -.
Accepts:
+456
00456
+1234
01234
All above may or may not followed by a -
Rejects:
0456
it should be:
00456 or+456 or04444
Number
A simple number with 8-20 digits.
Accepts:
00456-12345678
+457-12345678
+45712345678
0045712345678
99999999
Extend it?
Feel free, so you may include support for . or '(' separators. Just make sure you escape them, e.g. for ( use \(.
I don't know of such an API but it looks like could be done by using regular expressions. Probably you can't convert all numbers to a valid format but most of them.
The recent versions of http://code.google.com/p/libphonenumber/ have added metadata for many new countries and added a lot more detail for some of the countries previously listed.
The current source code version is r74 and the .jar file is at version 2.6. Previous .jar files were compiled for Java 1.6, but as of libphonenumber version 2.5.1 onwards they are now compiled for Java 1.5 and above.
Don't forget there is also a direct port of the code to JavaScript. It can be found in the source code tree at http://code.google.com/p/libphonenumber/source/browse/#svn%2Ftrunk%2Fjavascript
Bug reports are welcome. Updates to metadata are actively encouraged, as even the official government-published area code lists for many countries are either incomplete or out of date.
Don't re-invent the wheel; use an API, e.g. http://libphonenumber.googlecode.com/
This API gives you nice formatting, too.
Example:
String number = "(555) 478-1123";
PhoneNumberUtil phoneNumberUtil = PhoneNumberUtil.getInstance();
try {
Phonenumber.PhoneNumber phoneNumber = phoneNumberUtil.parse(number, Locale.US.getCountry());
} catch (NumberParseException e) {
// error handling
}
You could even use the phoneNumber object to nicely format it a valid phone number before saving it to the DB or whatever.
For French number which look like "01 44 55 66 77", we can use the following logic.
DecimalFormatSymbols dfs = new DecimalFormatSymbols();
dfs.setGroupingSeparator(' '); // sometimes '.' is used
DecimalFormat decfmt = new DecimalFormat("0,0", dfs); // enable grouping
decfmt.setMinimumIntegerDigits(10); // we always have 10 digits
decfmt.setGroupingSize(2); // necessary in order to group digits by 2 orders
System.out.println(decfmt.format(144556677)); // outputs "01 44 55 66 77"
Once this could be done, with google's phone number API the others mentioned, we can parse these sequences easily and reformat them into other forms such as "+33 1 44 55 66 77" like the following:
Iterable<PhoneNumberMatch> numbers = PhoneNumberUtil.getInstance().findNumbers(textWithPhoneNums, "FR");
for(Iterator<PhoneNumberMatch> iterator = numbers.iterator(); iterator.hasNext(); ){
PhoneNumberMatch pnm = iterator.next();
PhoneNumber number = pnm.number();
System.out.println(PhoneNumberUtil.getInstance().formatOutOfCountryCallingNumber(number, null));
}
I don't think there is a way of recognizing the lack of an area code unless your numbers are all from one country (presumably the USA), as each country has its own rules for things like area codes.
I'd start looking for detailed information here, here, and here - if there are APIs to handle it (in Java or otherwise), they might be linked to there as well.
There are commercial programs that format and validate international telephone numbers, like this one which even checks for valid area codes in some countries. For North America, the NANPA provides some resources for validating area codes.
The best i found was javax.telephony, to be found here: http://java.sun.com/products/javaphone/
It has an Address class, but sadly that class did not solve your problem :(
Well, maybe you can find a solution by digging deeper into it.
Apart of that, my first idea was to use regex. However, that seems to be a kind of bad solution to this specific problem.
My own needs were very simple. I just needed to take a 7 or 10-digit number and put separators (a dash, period, some string of characters, etc.) between the area code, exchange, and exchange number. Any value passed into the method that is not all digits or is not a length of 7 or 10 is simply returned. A null value returns an empty string and a null value for the separator is treated like an empty string. My code:
import java.util.regex.Matcher;
import java.util.regex.Pattern;
// ...
private String formatPhoneNumber(String phnumber, String separator) {
phnumber = (phnumber == null) ? "" : phnumber;
if ((phnumber.length() != 7) && (phnumber.length() != 10)) { return phnumber; }
// If we get here, 'phnumber' is for sure either 7 or 10 chars long
separator = (separator == null) ? "" : separator;
Pattern p = Pattern.compile("([0-9]*)");
Matcher m = p.matcher(phnumber);
if (m.matches()) {
if (phnumber.length() == 7) {
return phnumber.substring(0, 3) + separator + phnumber.substring(4);
} else {
return phnumber.substring(0, 3) + separator + phnumber.substring(3, 6)
+ separator + phnumber.substring(6);
}
// If we get here, it means 1 or more of the chars in 'phnumber'
// is not a digit and so 'phnumber' is returned just as passed in.
return phnumber;
}
I have created a Helper class using libphonenumber, But it is still on possibilities i.e (users mostly saves the local numbers in local contacts as local format) I mean without country code since it is local number but will save the International numbers with country code. and this helper works for both of these scenario's if the number is in global format it will simply keep it as it is while converts the local numbers to internal format. Below is the Code and Usage
class PhoneNumberHelper {
companion object {
fun correctNumber(number: String, context: Context): String? {
val code = StorageAdapter.get(context).userCountryCode
return validateNumber(number, code)
}
private fun validateNumber(number: String, mUserCountryCode: Int): String? {
return Utils.formatNumber(Utils.removeDelimetersFromNumber(number), mUserCountryCode)
}
fun formatNumber(destinationNumber: String, countryCode: Int): String? {
try {
val phoneUtil = PhoneNumberUtil.getInstance()
val regionCode = phoneUtil.getRegionCodeForCountryCode(countryCode)
var formattedNumber = formatNumber(destinationNumber, regionCode)
if (TextUtils.isEmpty(formattedNumber)) {
formattedNumber = destinationNumber
}
return formattedNumber
} catch (exp: Exception) {
Log.e("formatNumber", exp.toString())
}
return destinationNumber
}
fun formatNumber(destinationNumber: String, regionCode: String): String? {
if (TextUtils.isEmpty(regionCode)) {
return null
}
var number: String? = null
try {
val phoneUtil = PhoneNumberUtil.getInstance()
val phoneNumber = phoneUtil.parse(destinationNumber, regionCode)
if (phoneUtil.isValidNumber(phoneNumber)) {
/*
* E164 format is as per international format but no
* formatting applied e.g. no spaces in between
*/
number = phoneUtil.format(phoneNumber, PhoneNumberUtil.PhoneNumberFormat.E164)
number = number!!.replace("+", "00")
}
} catch (e: Exception) {
// number would be returned as null if it catches here
}
return number
}
}
}
Here Is how You will use it:
var globalnumber = PhoneNumberHelper.correctNumber(contact.mobile, context)
Clarification:
val code = StorageAdapter.get(context).userCountryCode
This is the Country code you should Store at during Signup. e.g. 0044 or +44
Don't forget to Include Dependency for libphone :
implementation 'com.googlecode.libphonenumber:libphonenumber:8.8.0'