libphonenumber - formatting phone numbers without knowing the country code - java

I have heard a lot of good from what appears to be an awesome library but I find myself in a delicate situation.
This is the first project I have ever worked where I am supposed to store phone numbers in a database.
I have read a bit about the E.164 format and I do intend to store all phone numbers using this format in my database.
The problem I am facing, is the data source. I have no control over the data source. All I known is that I am receiving a bunch of phone numbers and their format is not consistent. Some have the international extension, some don't. Some have parenthesis, hyphens, leading 0, etc. some don't.
How could I possibly extract the phone numbers from said source, format them into E.164 so that I can store them safely ?
I have tried using the PhoneNumberUtil#parse() method without providing the country code, since I don't have access to that information.
Have a look at the following example:
System.out.printLn("Number -> " + phoneNumberUtil.parse("00336555233634", null).toString())
Error type: INVALID_COUNTRY_CODE. Missing or invalid default region.
In my example, the number is that of french mobile phone. The two starting 0 works if you dial from outside France, I believe.
But the library cannot understand it as it is laking the country code.
Does that mean there does not exist a way to understand where that particular phone number is coming from ?
The documentation seems clear about it :
public PhoneNumber parse(CharSequence numberToParse, String defaultRegion)
#param defaultRegion region that we are expecting the number to be
from. This is only used if * the number being parsed is not
written in international format. The country_code for the *
number in this case would be stored as that of the default region
supplied. If the number * is guaranteed to start with a '+'
followed by the country calling code, then RegionCode.ZZ * or
null can be supplied.
So, if add the +33
System.out.printLn("Number -> " + phoneNumberUtil.parse("+336555233634", null).toString())
Then naturally the result is:
Number -> Country Code: 33 National Number: 336555233634
What should / can I do if the end-user supplies my app with phone numbers that do not start with + ? I cannot believe I am the only one if this situation.
Thanks for the help !

You need to use E164Format only. Here I took Norway as example
I have test case which tests and give the phone number in one format.
public static String getE164FormattedMobileNumber(String mobile, String locale)
throws PhoneNumberFormatException {
try {
PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance();
PhoneNumber phoneProto = phoneUtil.parse(mobile, locale);
if (phoneUtil.isValidNumber(phoneProto)
&& phoneUtil.isPossibleNumberForType(phoneProto, PhoneNumberType.MOBILE)) {
return phoneUtil.format(phoneProto, PhoneNumberFormat.E164);
}
throw new PhoneNumberFormatException(
"Mobile number is invalid with the provided locale");
} catch (NumberParseException e) {
throw new PhoneNumberFormatException("Error in parsing mobile number", e);
}
}
and the test case as follows.
// this is the test mobile used
private String expectedMobileNumber = "+4746205615";
private List<String> sucessMobileNumbers;
private List<String> failMobileNumbers;
public PhoneNumberE164FormatTest() {
sucessMobileNumbers =
Arrays.asList(
"46205615",
"004746205615",
"+4746205615",
"4746205615",
"46205615",
"+47 46205615",
"462 05 615");
failMobileNumbers = Arrays.asList("abcdsds3434", "abcdsds343?#4", "21448410", "9946739087");
}
#Test
public void e164FormattedMobileNumbersSucessCase() throws PhoneNumberFormatException {
for (String mobileNumber : sucessMobileNumbers) {
Assert.assertEquals(
expectedMobileNumber,
(PhoneNumberUtils.getE164FormattedMobileNumber(mobileNumber, NO)));
}
}
#Test(expected = PhoneNumberFormatException.class)
public void e164FormattedMobileNumbersFailCase() throws PhoneNumberFormatException {
for (String mobileNumber : failMobileNumbers) {
PhoneNumberUtils.getE164FormattedMobileNumber(mobileNumber, NO);
}
}

Store the original phone numbers in a non-operational column RAW_PHONE, and the canonical E.164 standardized number in you PHONE column ("00" -> "+", "(" -> "" and such). This way you are prepared for check lists and manual corrections, and improving the conversion.
Imaginable is having two phone columns in the table, and as second value just another extension -203.
Better not to fill the strict field if the conversion fails on country code or is otherwise dubious. Is the default France, or what when the user lives in Belgium?
One might argue that the source (location) of user registration determines the default country code.

Related

Spell-Check: Find one-to-one token difference mapping between two strings

I recently stumbled over this question on an internet archive and am having some difficulty wrapping my head around it. I want to find a desired mapping amongst the different tokens between two strings. The output should a String-to-String map.
For example:
String1: hewlottpackardenterprise helped american raleways in N Y
String2: hewlett packard enterprise helped american railways in NY
Output:
hewlottpackardenterprise -> hewlett packard enterprise
hewlott -> hewlett
raleways -> railways
N Y -> NY
Note: I have been able to write an edit-distance method, which finds all types of edits (segregated by types, like deletion, substitution etc.) and can convert the first string to second by a convert method
What have I tried so far?
Approach 1: I began with a naive approach of splitting both the strings by space, inserting the tokens of the first string into a hash map and comparing the tokens of the other string with this hashmap. However, this approach quickly fails as misses on relevant mappings.
Approach 2: I utilize my covert method to find the edit positions in the string, and type of edits. Using space edits, I'm able to create a mapping from hewlottpackardenterprise -> hewlett packardenterprise. However, the method just explodes as more and more things need to be splitted within the same word.
Appreciate any thoughts in this regard! Will clear any doubts in the comments.
public String returnWhiteSpaceEdittoken(EditDone e, List<String> testTokens) {
int pos = e.pos, count=0, i=0;
String resultToken = null;
if (e.type.equals(DeleteEdit)) {
for (i=0;i<testTokens.size();i++) {
count+=testTokens.get(i).length();
if (count==pos) {
break;
}
if (i!=testTokens.size()-1) {
count++;
}
}
resultToken = testTokens.get(i) + " " + testTokens.get(i+1);
} else if (e.type.equals(InsertEdit)) {
for (i=0;i<testTokens.size();i++) {
count+=testTokens.get(i).length();
if (count>pos) {
break;
}
if (i!=testTokens.size()-1) {
count++;
}
}
String token = testTokens.get(i);
resultToken = token.substring(count-token.length(), pos) + token.substring(pos, count);
}
return resultToken;
}
A pretty common way of handling problems like this is to find the longest common subsequence (or it's dual the shortest edit script) between the two strings and then post-process the output to get the specific format you want; in your case the string maps.
Wikipedia has a pretty decent introduction to the problem here: https://en.wikipedia.org/wiki/Longest_common_subsequence_problem
and a great paper "An O(ND) Difference Algorithm and Its Variations" by Myers can be found here. http://www.xmailserver.org/diff2.pdf

How to Validate Canadian postal Code in Java? Checking for 2 types of input? ex: accepting A1A1A1 and A1A 1A1

I am trying to make a program that allows the user to input 2 different formats for a postal code (A1A1A1 or A1A 1A1) and I cannot for the life of me get it to work :/
My thought process was identifying both formats first and then using an if statement to check for the identified formats and then decide if its valid or not.
But I keep getting invalid when I try to enter the format with space in them (A1A 1A1).
so far I have this
import java.util.Scanner;
import java.util.regex.Pattern;
public class ValidatingPostcodes {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("Please enter a Postcode:");
String Pc1 = "[A-Z][0-9][A-Z][0-9][A-Z][0-9]";
String Pc2 = "[A-Z][0-9][A-Z][ ][0-9][A-Z][0-9]";
while (sc.hasNext())
{ if (sc.hasNext (Pc1))
System.out.println ("Valid Postal Code");
else if (sc.hasNext (Pc2))
System.out.println ("Valid Postal Code");
else System.out.println("Invalid Postal Code");
sc.next();
}
}
}
The easy solution is: simply treat the two kinds of input the same way when processing them internally. Meaning:
Create one method that validates a 6-char potential ZIP code
But before calling that method, you check if your input contains a space as 4th character, and if so, you simply remove that space before giving it as parameter to your validation method.
But keep in mind: you probably want to keep the original string around - if you intend to give back "A1A A2A" later on. Of course, if you decide that users can enter ZIPs in two ways, but that they should get back "unified" format later on, then you can make that "space-dropping" thing permanent.
EDIT: you create a method
public boolean isValid(String zipCode) {
that returns TRUE for valid zipcodes that have 6 (SIX!) chars and no spaces
and another method
public String normalizeZipCode(String incoming) {
return incoming.replaceAll("\\s+","");
}
To be used like:
String zip1 = "A1A 1A1";
String zip2 = "A1A1A1";
String normalizedZip1 = normalizeZipCode(zip1);
String normalizedZip2 = normalizeZipCode(zip2);
System.out.println(isValid(normalizedZip1));
System.out.println(isValid(normalizedZip2));
The simple idea: if one format contains spaces, then just remove those spaces prior validation. In other words: you allow the user to enter data in two formats; but internally, you make sure that any usage of the second format is simply avoided, by turning it into the format that comes without spaces.

Why do i get a "terminated due to timeout" error for my code at hackerrank?

I got a "Terminated due to timeout error" when i ran my code for some specific testcases only. Even though my code compiled successfully for other testcases. Can someone please help me with this?
Link - https://www.hackerrank.com/challenges/phone-book
Problem Statement :
You are given a phone book that consists of people's names and their phone number. After that you will be given some person's name as query. For each query, print the phone number of that person.
Input Format :
The first line will have an integer denoting the number of entries in the phone book. Each entry consists of two lines: a name and the corresponding phone number.
After these, there will be some queries. Each query will contain a person's name. Read the queries until end-of-file.
Constraints:
1<=n<=100000
1<=Query<=100000
A person's name consists of only lower-case English letters and it may be in the format 'first-name last-name' or in the format 'first-name'. Each phone number has exactly 8 digits without any leading zeros.
Output Format :
For each case, print "Not found" if the person has no entry in the phone book. Otherwise, print the person's name and phone number. See sample output for the exact format.
To make the problem easier, we provided a portion of the code in the editor. You can either complete that code or write completely on your own.
My code is as follows :
import java.util.*;
import java.io.*;
class Solution
{
public static void main(String []args)
{
Scanner in = new Scanner(System.in);
int n=in.nextInt();
in.nextLine();
ArrayList<String> name = new ArrayList<String>();
int[] phone = new int[100000];
for(int i=0;i<n;i++)
{
name.add(in.nextLine());
phone[i]=in.nextInt();
in.nextLine();
}
while(in.hasNext())
{
String s=in.nextLine();
int a=name.indexOf(s);
if(a>=0)
{
System.out.println(s + "=" + phone[a] );
}
else
{
System.out.println("Not found");
}
}
}
}
PS:This is my first question on the forum. I'm an amateur learning java. Sorry if i violated any of the many rules of asking a question :( . Please do correct me and help me contribute to the community here in a good way :)
The problem with your logic is that it is implemented using ArrayList which is a sequential structure. Any search in List will be sequential and for large test cases its taking too much time to lookup in your names list.
Hash map is more appropriate for a phone book example as it keeps data in key, value pair and look ups are fast because of hashing
Here is a version that is implemented using HashMap
Map<String,Integer> phonebook = new HashMap<>();
Scanner in = new Scanner(System.in);
int n=in.nextInt();
in.nextLine();
for(int i=0;i<n;i++)
{
String name=in.nextLine();
int phone=in.nextInt();
in.nextLine();
phonebook.put(name,phone);
}
while(in.hasNext())
{
String s=in.nextLine();
Integer phone = phonebook.get(s);
if(phone==null){
System.out.println("Not found");
} else {
System.out.println(s+"="+phone);
}
}
Hope this explains.
Usually "Terminated due to timeout error" occurs when your code takes longer time to execute than the maximum time set by the Problem Setters(Hackerrank).
The problem you tried is intended to teach you how HashMaps are used, but you solved the problem using arrays. Searching in arrays takes O(n)longer time than that of Maps which are generally hashed to search in O(1) time. For smaller input your program works fine, but for larger inputs like 100000 entries, It will take longer time and result in time out. So Use Maps instead of Arrays and ArrayLists

How to validate phone number in android application?

I am working on android. In my app users will register by entering their phone number in edittext. This phone number is then saved in database. Now when the user login with the app, I am getting the list of contacts from his mobile and comparing that with the people who register with this app. If the number in the contacts list matches with the number in the database, then I need to display those numbers in listview. Here the problem is if the user save his number with +91 or with 0 before his contact then the number in the database is not matching with the contact. At that time the numbers are not displaying.
For this issue, Do we need to keep any alert before entering the number in edit text? For example in edit text I gave, Ph no: 8923458128 and the saved it in database. Now I logged in with this number and my contacts list for suppose
9823484586
+919988334856
Lets say the above 2 numbers are stored in database. But the 2nd contact , the user entered as 9988334856 without +91. Then finally in the listview instead of 2 numbers only 1 number is displaying as the second number is not matching with database number.
How can I solve this issue? Please help me in this regard.
If you are fetching all phones from DB, then you can use below code to match entered phone with phone from DB using PhoneNumberUtils.compare()
It compares phone numbers a and b, return true if they're identical
enough for caller ID purposes.
private String getMatchedPhones(ArrayList<String> contactsFromDB, String phoneToMatch) {
// Iterate all numbers and match
for (String numberFromDb : contactsFromDB) {
if (PhoneNumberUtils.compare(numberFromDb, phoneToMatch)) {
return phoneToMatch; // Or numberFromDb
}
}
return null; // Or can custom msg. If not matched.
}
I think best way to do it create your table with 4 column-
1)id
2)name(if needed)
3)country-code
4)phone number
And now on your UI prefix country code in a spiner and give phone-number type of field in a textview. And in your database use integer value to store number.
And from matching your phone number just pass this query-
1)phoneNumber = phoneNumberEditText.getText().toString();
2)
// Reading all contacts from database
List<Contacts> number = db.getAllNumber();
for (final Contacts cn : number) {
if ((phoneNumber.equals(cn.getNumber()){
//do what you want
}
}
Thanks!Hope it will help you.
Put these two lines in your XML file at that phone number edit text field
android:inputType="numberDecimal"
android:maxLength="10"
then he could not enter more than 10 numbers and only he should enter numbers.
you can take country code in one more text field and validate with it.
For an Mobile number validation android provide InBuilt Patterns.But it only works in API level 8 and above.Try below one line code.
/* method for phone number validation */
private Boolean Number_Validate(String number)
{
return !TextUtils.isEmpty(number) && (number.length()==10) && android.util.Patterns.PHONE.matcher(number).matches();
}
you can call this mehtod by passing number in parameter,it return either true or false.
Number_Validate(number);
Hope you get your answer.
Thanks.
Use TEXT not Int in your database. When you use Int, if the first number is 0 it will disregard so just use TEXT.
private boolean phvalidator(String ph2) {
// TODO Auto-generated method stub
String expression = "^[0-9-1+]{10,15}$";
CharSequence inputStr = ph;
Pattern pattern = Pattern.compile(expression,Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(inputStr);
return (matcher.matches())? true : false;
try this
final String mobile = emobile.getText().toString();
if (!isValidMobile(mobile)){
emobile.setError("Invalid Mobile");
}
private boolean isValidMobile(String mobile) {
if (!TextUtils.isEmpty(mobile)) {
return Patterns.PHONE.matcher(mobile).matches();
}
return false;
}

Check valid IPv4 Address in Java

I am using the sun.net.util.IPAddressUtil package to check whether the string contains a valid IPv4 and IPv6 address or not.
Code Snippet is:-
String ipv4addr="200";
if(IPAddressUtil.isIPv4LiteralAddress(ipv4addr))
{
System.out.println("valid ipv4 address");
}
else
{
System.out.println("not valid");
}
But for addresses such as 200 and 300 it is still saying it is a valid IPv4 address, which it isn't.
When I used the same package and checked for IPV6 address using :-
String ipv6addr="200";
if(IPAddressUtil.isIPv6LiteralAddress(ipv6addr))
{
System.out.println("valid ipv6 address");
}
else
{
System.out.println("not valid");
}
I get the correct result. However, IPv4 does not seem to be working or may be I am using it incorrectly. Please guide me. I don't want to use regex for IPv4 validation...
There's a reason you're getting a "valid" result: 200 is a valid IPv4 address.
See, to the computer, an IPv4 address is just a 32-bit number. The dots are entirely for our convenience, because we humans suck at memorizing big precise numbers. But they don't have to be there; there are rules about how an address gets parsed depending on how many parts it has.
When an address consists of one number, it's considered a 32-bit number, and each byte is 8 bits of that number. If you were to parse "200" as an IP address, it would be equivalent to 0.0.0.200. Likewise, "2130706433" would be equivalent to 127.0.0.1.
There are also standards for when an address has two parts like 0.200 (first part is the first byte, and the second part is a 24-bit number representing the other 3 bytes), and even 0.0.200 (first two numbers are bytes, the last part is 16 bits and takes up the other 2 bytes). The "unusual" formats are leftovers from the days of IP address classes, but almost all software that has to parse addresses will understand them. (If you pop open your browser and go to http://1249739112* or even http://74.125.33128*, for example, Google's home page will come up.)
* See the comments for clickable links. Thanks, "link validator". :P
See http://download.oracle.com/javase/6/docs/api/java/net/Inet4Address.html or http://www.perlmonks.org/?node_id=221512, or http://en.wikipedia.org/wiki/IPv4#Address_representations, for some more details.
Java understands these formats as well (as does .net, as well as any decent OS), and parses the address correctly whether it contains 1, 2, 3, or 4 parts.
If you want to check that a would-be address actually looks like "xxx.xxx.xxx.xxx", then you'll probably want to explicitly check that using a pattern, or using a validation library that considers 32-bit numbers as invalid addresses (even though they are valid). I wouldn't bother, though -- if you use the lookup functions provided, you can accept an address in any standard format and it will work.
(All this mess changes with IPv6; there's a much stricter format, and you can't just type in some 36-digit number and expect it to work. But the platform still knows how to parse an address, and you should trust it to do so.)
Check out Guava's InetAddresses class which contains static utility methods for working with IP addresses. (As I understand it uses the sun.net.util.IPAddressUtil class behind the scenes.)
System.out.println(InetAddresses.isInetAddress("400")); // false
It's not a good idea to use internal "sun" packaged classes, I'd try using Apache's Validator
http://commons.apache.org/validator/
which has IP Address validation.
If you want to validate if a string is valid IP address representation, the source code of org.apache.http.conn.util.InetAddressUtils uses these regular expressions:
IPV4_PATTERN = Pattern.compile(
"^(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)(\\.(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)){3}$");
IPV6_STD_PATTERN = Pattern.compile(
"^(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$");
IPV6_HEX_COMPRESSED_PATTERN = Pattern.compile(
"^((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)::((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)$");
That string is an IPv4 string format that was originally introduced by the aton_inet utility in BSD Unix and has persisted until this day in the various Unix and Linux flavours and elsewhere.
https://linux.die.net/man/3/inet_aton
The IPAddress Java library will do validation that can be configured to support aton_inet formats or not. The javadoc is available at the link. Disclaimer: I am the project manager.
Verify if an address is valid, allow inet_aton style:
String str = "200";
IPAddressString addrString = new IPAddressString(str);
try {
IPAddress addr = addrString.toAddress();
System.out.println("valid address: " + addr.toCanonicalString());
} catch(IPAddressStringException e) {
System.out.println(e.getMessage());
}
Output:
valid address: 0.0.0.200
Verify if an address is valid, do not allow inet_aton style:
IPAddressStringParameters parameters = new
IPAddressStringParameters.Builder().allow_inet_aton(false).toParams();
addrString = new IPAddressString(str, parameters);
try {
IPAddress addr = addrString.toAddress();
System.out.println("valid address: " + addr.toCanonicalString());
} catch(IPAddressStringException e) {
System.out.println(e.getMessage());
}
Output:
200 IP Address error: options do not allow IPv4 address with less than four segments
After a small research I ended up with something like this
public static boolean isValidIP4Address(String ipAddress) {
if (ipAddress.matches("^(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$")) {
String[] groups = ipAddress.split("\\.");
for (int i = 0; i <= 3; i++) {
String segment = groups[i];
if (segment == null || segment.length() <= 0) {
return false;
}
int value = 0;
try {
value = Integer.parseInt(segment);
} catch (NumberFormatException e) {
return false;
}
if (value > 255) {
return false;
}
}
return true;
}
return false;
}
which was fine for simple checks.

Categories

Resources