There are some related questions on SO but I think this one is actually unique. I'm working on a system where we expect to get decimal input from users in their own locale.
We have a user in Canada who is used to entering numbers in French-style (e.g. 12,5 is a number between 12 and 13) and when they enter that number into our system while in the "French" locale, it gets parsed as a number between 12 and 13. When switching into English and entering "12,5", the number gets parsed as 125, ten times as large as expected.
The problem is that the set of number format symbols being used is different and has bearing on how the parsing is performed. In French, the , character causes the parser to switch from parsing the whole-part to parsing the decimal-part. In English, the , is an ignoreable "grouping separator".
I'd like to throw an error when an English user enters "12,5" because we only expect commas to occur when there are 3 digits after it without any other markers, end-of-input, etc.
I want to be very strict, here, because I want to remove the ambiguity from a number like "12,5" in English. Was that a fat-finger and it should have been "12.5" or is that a French-language used thinking that they are entering a number between 12 and 13. I'd like to throw an error and make sure that the user is entering exactly the type of input that the software is expecting to parse.
Is there a way to get DecimalFormat to do this for me, or do I have to roll my own additional validation?
How do I assign same numbers in different formats to one contact?
In the stock Samsung phone app,
+1 8542569, 8542569 and 18542569 are all assigned to one contact when called: "Example USA" :
Even though "Example USA" only has +1 854-256-9 listed in the phone book:
This goes on for every country, not just the USA. Here's a New Zealand example:
^ Here, "New Zealand Example" has 91234567 listed.
And, I can call 91234567, 00 64 9-123 4567 or 6491234567 and they will all get assigned to "New Zealand Example" contact:
My question is: how can I do the same thing in Java, for every country just like the Samsung stock app?
Say I have 3 strings: 91234567, 00 64 9-123 4567 and 6491234567.
How will my app recognize that they belong to the same contact and that they're basically the same number?
I'm sure it can be done because Samsung did it :)
Again, I'd like the code to work for every country.
Part 1: Remove starting zeros. They are useless. They might be useful, but it would be easier to do it by removing them.
This quora link with be a bit useful
Now countries have different number of digits in their phone numbers. Like, India has 10 which doesn't match New Zealand and USA.
Assuming that each country has a specific number of digits in numbers after removing region specific codes.
Part 2: You can create a multi-dimensional matrix, with country code and number of digits after that. Match for starting country codes, and then verify number of digits.
This method may have conflicts with different countries, but I lack knowledge about this thing.
Eg. of conflict:
Country A: country_code = +1, digits = 6
Country B: country_code = +12, digits =5
+1 234567
+12 34567
How to use User Data(UDH) in smpp? Now I want to send sms specified port.
I use OpenSMPP as my project lib..
Follow these steps to send UDH over SMPP:
Set the UDHI bit to 1 on the esm_class field. The simplest way to do this - esm_class = esm_class | 0x40.
Put UDH at the beginning of short_message field. Read on for a quick summary. See the references to know in details how to encode UDH.
Here is how to encode UDH:
The first byte of UDH must mention the length (in bytes) of remaining part of UDH. Since you may not know this ahead, you may have to calculate it later on.
Then follows one or more IE (Information Element). Each IE has 3 parts:
First byte: IEI (IE Indicator). Identifies the element you want to encode. There are established IEI.
Second byte: IEIDL (IEI Data Length). Identifies the number of bytes that holds the data part. Each established IEI has fixed value for this field.
Third byte and rest part: IEID (IEI Data): Holds the data part. Each established IEI has fixed format of the data.
Count the total bytes consumed by each IE and put the result in the first byte.
For sending SMS to a part, you can use IEI 0x04 or 0x05. I have only seen 0x05 being used.
References
3GPP specification: 23.040
User Data Header
I have a flat file of e-mail header data that I'm trying to parse for analysis. The file will always have fields in order as follows: Record Number, 1 or 2 bytes, "From:" followed by the sender's name and "Sent:" followed by the date sent.
1 From: Person.Name Sent: April 12, 2010
2 From:<tab>Person.Name Sent: April 30, 2011
10 From: Person.Name Sent: June 29, 2012
11 From:<tab>Person.Name Sent: July 8, 2012
Using BufferedReader I am reading a the file line-by-line and defining a substring of the Name based on all characters between the indeces of "From:" and "Sent:".
String sender = inputLine.substring((inputLine.indexof("From:")+6),(inputLine.indexOf("Sent:")-1));
In this case, I'm grabbing everything AFTER "From: " (sixth byte excludes the word, the colon, and the space/single byte after the colon) through one LESS than the position of "Sent: " (the space before the S).
However, I'm getting unexpected output when I run the job. Some of my input data appears to have a tab after "From: " and some lines do not. When a tab is present, my output include the last two or three bytes of "From: " (when the record number is a single digit, I get m:<tab>, for double digit record numbers it's om:<tab>.
Person.Name
m:<tab>Person.Name <-- single digit record number
Person.Name
om:<tab>Person.Name <-- double digit record number
EDIT: When I amend my substring to
String sender = inputLine.substring((inputLine.indexof("From:\t")+6),(inputLine.indexOf("Sent:")-1));
ONLY the records with a space (and not a tab) prepent the end of the From: to the output.
Person.Name <-- records with From:<tab>
om: Person.Name <-- records with From:<space>
I'm now wondering if I understand substring correctly. My statement above is based on an understanding of substring(x,y) where x is the start and y is the end of the string. Is that correct?
Since indexOf("From:") is intended to represent an integer value of 2 or 3 (depending on a 1 or 2 byte record number, e.g., 1 From: or 10 From:) I would think that adding a value of 6 would give me an index value that falls AFTER the : in index 8 or 9 from the front of the line. So why does it appear to be viewing this as an index of 5--regardless?
111111111122222222222 |
0123456789012345678901234567890 + index values
1 From: Person.Name Sent: June
10 From: Person.Name Sent: July
The tab is the only difference in the records, and while I understand that a tab character may need to be counted differently than an ASCII space character, SUBTRACTING from the index seems a little strange.
Even more interesting, if I remove the "adjustments" from the statement,
String sender = inputLine.substring((inputLine.indexof("From:")),(inputLine.indexOf("Sent:")));
I get a -1 out of range exception.
Can someone please explain what's happening here? I am baffled, and can't find answers this specific in oracle's java documentation.
I ended up creating new input fields that replaced \t with a space. Then everything worked fine. What it was about the tab character that threw things off is still a mystery.
What is the best way for converting phone numbers into international format (E.164) using Java?
Given a 'phone number' and a country id (let's say an ISO country code), I would like to convert it into a standard E.164 international format phone number.
I am sure I can do it by hand quite easily - but I would not be sure it would work correctly in all situations.
Which Java framework/library/utility would you recommend to accomplish this?
P.S. The 'phone number' could be anything identifiable by the general public - such as
* (510) 786-0404
* 1-800-GOT-MILK
* +44-(0)800-7310658
that last one is my favourite - it is how some people write their number in the UK and means that you should either use the +44 or you should use the 0.
The E.164 format number should be all numeric, and use the full international country code (e.g.+44)
Google provides a library for working with phone numbers. The same one they use for Android
http://code.google.com/p/libphonenumber/
String swissNumberStr = "044 668 18 00"
PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance();
try {
PhoneNumber swissNumberProto = phoneUtil.parse(swissNumberStr, "CH");
} catch (NumberParseException e) {
System.err.println("NumberParseException was thrown: " + e.toString());
}
// Produces "+41 44 668 18 00"
System.out.println(phoneUtil.format(swissNumberProto, PhoneNumberFormat.INTERNATIONAL));
// Produces "044 668 18 00"
System.out.println(phoneUtil.format(swissNumberProto, PhoneNumberFormat.NATIONAL));
// Produces "+41446681800"
System.out.println(phoneUtil.format(swissNumberProto, PhoneNumberFormat.E164));
Speaking from experience at writing this kind of thing, it's really difficult to do with 100% reliability. I've written some Java code to do this that is reasonably good at processing the data we have but won't be applicable in every country. Questions you need to ask are:
Are the character to number mappings consistent between countries? The US uses a lot of this (eg 1800-GOT-MILK) but in Australia, as one example, its pretty rare. What you'd need to do is ensure that you were doing the correct mapping for the country in question if it varies (it might not). I don't know what countries that use different alphabets (eg Cyrilic in Russia and the former Eastern block countries) do;
You have to accept that your solution will not be 100% and you should not expect it to be. You need to take a "best guess" approach. For example, theres no real way of knowing that 132345 is a valid phone number in Australia, as is 1300 123 456 but that these are the only two patterns that are for 13xx numbers and they're not callable from overseas;
You also have to ask if you want to validate regions (area codes). I believe the US uses a system where the second digit of the area code is a 1 or a 0. This may have once been the case but I'm not sure if it still applies. Whatever the case, many other countries will have other rules. In Australia, the valid area codes for landlines and mobile (cell) phones are two digits (the first is 0). 08, 03 and 04 are all valid. 01 isn't. How do you cater for that? Do you want to?
Countries use different conventions no matter how many digits they're writing. You have to decide if you want to accept something other than the "norm". These are all common in Australia:
(02) 1234 5678
02 1234 5678
0411 123 123 (but I've never seen 04 1112 3456)
131 123
13 1123
131 123
1 300 123 123
1300 123 123
02-1234-5678
1300-234-234
+44 78 1234 1234
+44 (0)78 1234 1234
+44-78-1234-1234
+44-(0)78-1234-1234
0011 44 78 1234 1234 (0011 is the standard international dialling code)
(44) 078 1234 1234 (not common)
And thats just off the top of my head. For one country. In France, for example, its common the write the phone number in number pairs (12 34 56 78) and they pronounce it that way too: instead of:
un (one), deux (two), trois (three), ...
its
douze (twelve), trente-quatre (thirty four), ...
Do you want to cater for that level of cultural difference? I would assume not but the question is worth considering just in case you make your rules too strict.
Also some people may append extension numbers on phone numbers, possibly with "ext" or similar abbreviation. Do you want to cater for that?
Sorry, no code here. Just a list of questions to ask yourself and issues to consider. As others have said, a series of regular expressions can do much of the above but ultimately phone number fields are (mostly) free form text at the end of the day.
This was my solution:
public static String FixPhoneNumber(Context ctx, String rawNumber)
{
String fixedNumber = "";
// get current location iso code
TelephonyManager telMgr = (TelephonyManager) ctx.getSystemService(Context.TELEPHONY_SERVICE);
String curLocale = telMgr.getNetworkCountryIso().toUpperCase();
PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance();
Phonenumber.PhoneNumber phoneNumberProto;
// gets the international dialling code for our current location
String curDCode = String.format("%d", phoneUtil.getCountryCodeForRegion(curLocale));
String ourDCode = "";
if(rawNumber.indexOf("+") == 0)
{
int bIndex = rawNumber.indexOf("(");
int hIndex = rawNumber.indexOf("-");
int eIndex = rawNumber.indexOf(" ");
if(bIndex != -1)
{
ourDCode = rawNumber.substring(1, bIndex);
}
else if(hIndex != -1)
{
ourDCode = rawNumber.substring(1, hIndex);
}
else if(eIndex != -1)
{
ourDCode = rawNumber.substring(1, eIndex);
}
else
{
ourDCode = curDCode;
}
}
else
{
ourDCode = curDCode;
}
try
{
phoneNumberProto = phoneUtil.parse(rawNumber, curLocale);
}
catch (NumberParseException e)
{
return rawNumber;
}
if(curDCode.compareTo(ourDCode) == 0)
fixedNumber = phoneUtil.format(phoneNumberProto, PhoneNumberFormat.NATIONAL);
else
fixedNumber = phoneUtil.format(phoneNumberProto, PhoneNumberFormat.INTERNATIONAL);
return fixedNumber.replace(" ", "");
}
I hope this helps someone with the same problem.
Enjoy and use freely.
Thanks for the answers. As stated in the original question, I am much more interested in the formatting of the number into the standard format than I am in determining if it is a valid (as in genuine) phone number.
I have some hand crafted code currently that takes a phone number String (as entered by the user) and a source country context and target country context (the country from where the number is being dialed, and the country to where the number is being dialed - this is known to the system) and then does the following conversion in steps
Strip all whitespace from the number
Translate all alpha into digits - using a lookup table of letter to digit (e.g. A-->2, B-->2, C-->2, D-->3) etc. for the keypad (I was not aware that some keypads distribute these differently)
Strip all punctuation - keeping a preceding '+' intact if it exists (in case the number is already in some sort of international format).
Determine if the number has an international dialling prefix for the country context - e.g. if source context is the UK, I would see if it starts with a '00' - and replace it with a '+'. I do not currently check whether the digits following the '00' are followed by the international dialing code for the target country. I look up the international dialing prefix for the source country in a lookup table (e.g. GB-->'00', US-->'011' etc.)
Determine if the number has a local dialing prefix for the country context - e.g. if the source context is the UK, I would look to see if it starts with a '0' - and replace it with a '+' followed by the international dialing code for the target country. I look up the local dialing prefix for the source country in a lookup table (e.g. GB-->'0', US-->'1' etc.), and the international dialing code for the target country in another lookup table (e.g.'GB'='44', US='1')
It seems to work for everything I have thrown at it so far - except for the +44(0)1234-567-890 situation - I will add a special case check for that one.
Writing it was not hard - and I can add special cases for each strange exception I come across. But I would really like to know if there is a standard solution.
The phone companies seem to deal with this thing every day. I never get inconsistent results when dialing numbers using the PSTN. For example, in the US (where mobile phones have the same area codes as landlines, I could dial +1-123-456-7890, or 011-1-123-456-7890 (where 011 is the international dialing prefix in the US and 1 is the international dialing code for the US), 1-123-456-7890 (where 1 is the local dialing prefix in the US) or even 456-7890 (assuming I was in the 123 area code at the time) and get the same results each time. I assume that internally these dialed numbers get converted to the same E.164 standard format, and that the conversion is all done in software.
To be honest, it sounds like you've got most of the bases covered already.
The +44(0)800 format sometimes (incorrectly) used in the UK is annoying and isn't strictly valid according to E.123, which is the ITU-T recommendation for how numbers should be displayed. If you haven't got a copy of E.123 it's worth a look.
For what it's worth, the telephone network itself doesn't always use E.164. Often there'll be a flag in the ISDN signalling generated by the PBX (or in the network if you're on a steam phone) which tells the network whether the number being dialled is local, national or international.
In some countries you can validate 112 as a valid phone number, but if you stick a country code in front of it it won't be valid any more. In other countries you can't validate 112 but you can validate 911 as a valid phone number.
I've seen some phones that put Q on the 7 key and Z on the 9 key. I've seen some phones that put Q and Z on the 0 key, and some that put Q and Z on the 1 key.
An area code that existed yesterday might not exist today, and vice-versa.
In half of North America (country code 1), the second digit rule used to be 0 or 1 for area codes, but that rule went away 10 years ago.
I'm not aware of a standard library or framework available for formatting telephone numbers into E.164.
The solution used for our product, which requires formatting PBX provided caller-id into E.164, is to deploy a file (database table) containing the E.164 format information for all countries applicable.
This has the advantage that the application can be updated (to handle all the strange corner cases in various PSTN networks) w/out requiring changes to the production code base.
The table contains a row for each country code and information regarding area code length and subscriber length. There may be multiple entries for a country depending on what variations are possible with area code and subscriber number lengths.
Using New Zealand PSTN (partial) dial plan as an example of the table..
CC AREA_CODE AREA_CODE_LENGTH SUBSCRIBER SUBSCRIBER_LENGTH
64 1 7
64 21 2 7
64 275 3 6
We do something similar to what you have described, i.e. strip the provided telephone number of any non-digit characters and then format based on various rules regarding overall number plan length, outside access code, and long distance/international access codes.