philip.liard@gmail.com | 80d738a | 2011-09-14 10:42:59 +0000 | [diff] [blame] | 1 | // Copyright (C) 2011 The Libphonenumber Authors |
| 2 | // |
| 3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | // you may not use this file except in compliance with the License. |
| 5 | // You may obtain a copy of the License at |
| 6 | // |
| 7 | // http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | // |
| 9 | // Unless required by applicable law or agreed to in writing, software |
| 10 | // distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | // See the License for the specific language governing permissions and |
| 13 | // limitations under the License. |
| 14 | |
| 15 | // A formatter which formats phone numbers as they are entered. |
| 16 | // |
| 17 | // An AsYouTypeFormatter can be created by invoking the GetAsYouTypeFormatter |
| 18 | // method of the PhoneNumberUtil. After that digits can be added by invoking the |
| 19 | // InputDigit method on the formatter instance, and the partially formatted |
| 20 | // phone number will be returned each time a digit is added. The Clear method |
| 21 | // can be invoked before a new number needs to be formatted. |
| 22 | // |
| 23 | // See AYTF_US, AYTF_GBFixedLine and AYTF_DE test functions in |
| 24 | // asyoutypeformatter_test.cc for more details on how the formatter is to be |
| 25 | // used. |
| 26 | // |
lararennie@google.com | 35bd393 | 2012-09-06 09:48:57 +0000 | [diff] [blame] | 27 | // This is a direct port from AsYouTypeFormatter.java. |
| 28 | // Changes to this class should also happen to the Java version, whenever it |
| 29 | // makes sense. |
philip.liard@gmail.com | 80d738a | 2011-09-14 10:42:59 +0000 | [diff] [blame] | 30 | // |
| 31 | // This class is NOT THREAD SAFE. |
| 32 | |
| 33 | #ifndef I18N_PHONENUMBERS_ASYOUTYPEFORMATTER_H_ |
| 34 | #define I18N_PHONENUMBERS_ASYOUTYPEFORMATTER_H_ |
| 35 | |
| 36 | #include <list> |
| 37 | #include <string> |
| 38 | |
philip.liard@gmail.com | af4a2ce | 2013-04-30 11:35:55 +0000 | [diff] [blame] | 39 | #include "phonenumbers/base/basictypes.h" |
| 40 | #include "phonenumbers/base/memory/scoped_ptr.h" |
philip.liard@gmail.com | 80d738a | 2011-09-14 10:42:59 +0000 | [diff] [blame] | 41 | #include "phonenumbers/regexp_adapter.h" |
| 42 | #include "phonenumbers/regexp_cache.h" |
| 43 | #include "phonenumbers/phonemetadata.pb.h" |
| 44 | #include "phonenumbers/unicodestring.h" |
| 45 | |
| 46 | namespace i18n { |
| 47 | namespace phonenumbers { |
| 48 | |
| 49 | using std::list; |
| 50 | using std::string; |
| 51 | |
| 52 | class PhoneNumberUtil; |
| 53 | |
| 54 | class AsYouTypeFormatter { |
| 55 | public: |
| 56 | ~AsYouTypeFormatter() {} |
| 57 | |
| 58 | // Formats a phone number on-the-fly as each digit is entered. |
| 59 | // next_char is the most recently entered digit of a phone number. Formatting |
| 60 | // characters are allowed, but as soon as they are encountered this method |
| 61 | // formats the number as entered and not "as you type" anymore. Full width |
| 62 | // digits and Arabic-indic digits are allowed, and will be shown as they are. |
| 63 | // Returns the partially formatted phone number (which is a reference to the |
| 64 | // given string parameter for convenience). |
| 65 | const string& InputDigit(char32 next_char, string* result); |
| 66 | |
| 67 | // Same as InputDigit, but remembers the position where next_char is inserted, |
| 68 | // so that it could be retrieved later by using GetRememberedPosition(). The |
| 69 | // remembered position will be automatically adjusted if additional formatting |
| 70 | // characters are later inserted/removed in front of next_char. |
| 71 | // Returns the partially formatted phone number (which is a reference to the |
| 72 | // given string parameter for convenience). |
| 73 | const string& InputDigitAndRememberPosition(char32 next_char, string* result); |
| 74 | |
| 75 | // Returns the current position in the partially formatted phone number of the |
| 76 | // character which was previously passed in as the parameter of |
| 77 | // InputDigitAndRememberPosition(). |
| 78 | int GetRememberedPosition() const; |
| 79 | |
| 80 | // Clears the internal state of the formatter, so it could be reused. |
| 81 | void Clear(); |
| 82 | |
| 83 | private: |
| 84 | // Constructs an as-you-type formatter. Should be obtained from |
| 85 | // PhoneNumberUtil::GetAsYouTypeFormatter(). |
| 86 | explicit AsYouTypeFormatter(const string& region_code); |
| 87 | |
| 88 | // Returns the metadata corresponding to the given region code or empty |
| 89 | // metadata if it is unsupported. |
| 90 | const PhoneMetadata* GetMetadataForRegion(const string& region_code) const; |
| 91 | |
| 92 | // Returns true if a new template is created as opposed to reusing the |
| 93 | // existing template. |
| 94 | bool MaybeCreateNewTemplate(); |
| 95 | |
| 96 | void GetAvailableFormats(const string& leading_three_digits); |
| 97 | |
| 98 | void NarrowDownPossibleFormats(const string& leading_digits); |
| 99 | |
lararennie@google.com | 35bd393 | 2012-09-06 09:48:57 +0000 | [diff] [blame] | 100 | // Calculates whether we should be adding a space after the national prefix |
| 101 | // for this formatting rule or not. |
| 102 | void SetShouldAddSpaceAfterNationalPrefix(const NumberFormat& format); |
| 103 | |
philip.liard@gmail.com | 80d738a | 2011-09-14 10:42:59 +0000 | [diff] [blame] | 104 | bool CreateFormattingTemplate(const NumberFormat& format); |
| 105 | |
| 106 | // Gets a formatting template which could be used to efficiently format a |
| 107 | // partial number where digits are added one by one. |
| 108 | void GetFormattingTemplate(const string& number_pattern, |
| 109 | const string& number_format, |
| 110 | UnicodeString* formatting_template); |
| 111 | |
| 112 | void InputDigitWithOptionToRememberPosition(char32 next_char, |
| 113 | bool remember_position, |
| 114 | string* phone_number); |
| 115 | |
philip.liard@gmail.com | 7094201 | 2011-09-16 10:22:04 +0000 | [diff] [blame] | 116 | void AttemptToChoosePatternWithPrefixExtracted(string* formatted_number); |
| 117 | |
| 118 | // Some national prefixes are a substring of others. If extracting the |
| 119 | // shorter NDD doesn't result in a number we can format, we try to see if we |
| 120 | // can extract a longer version here. |
| 121 | bool AbleToExtractLongerNdd(); |
| 122 | |
lararennie@google.com | 35bd393 | 2012-09-06 09:48:57 +0000 | [diff] [blame] | 123 | // Check to see if there is an exact pattern match for these digits. If so, we |
| 124 | // should use this instead of any other formatting template whose |
| 125 | // leadingDigitsPattern also matches the input. |
philip.liard@gmail.com | 80d738a | 2011-09-14 10:42:59 +0000 | [diff] [blame] | 126 | void AttemptToFormatAccruedDigits(string* formatted_number); |
| 127 | |
lararennie@google.com | 35bd393 | 2012-09-06 09:48:57 +0000 | [diff] [blame] | 128 | // Combines the national number with any prefix (IDD/+ and country code or |
| 129 | // national prefix) that was collected. A space will be inserted between them |
| 130 | // if the current formatting template indicates this to be suitable. |
| 131 | // The result will be stored in phone_number. |
| 132 | void AppendNationalNumber(const string& national_number, |
| 133 | string* phone_number) const; |
| 134 | |
philip.liard@gmail.com | 80d738a | 2011-09-14 10:42:59 +0000 | [diff] [blame] | 135 | // Attempts to set the formatting template and assigns the passed-in string |
| 136 | // parameter to the formatted version of the digits entered so far. |
| 137 | void AttemptToChooseFormattingPattern(string* formatted_number); |
| 138 | |
| 139 | // Invokes InputDigitHelper on each digit of the national number accrued, and |
| 140 | // assigns the passed-in string parameter to a formatted string in the end. |
| 141 | void InputAccruedNationalNumber(string* number); |
| 142 | |
lararennie@google.com | 35bd393 | 2012-09-06 09:48:57 +0000 | [diff] [blame] | 143 | // Returns true if the current country is a NANPA country and the national |
| 144 | // number begins with the national prefix. |
| 145 | bool IsNanpaNumberWithNationalPrefix() const; |
| 146 | |
philip.liard@gmail.com | 7094201 | 2011-09-16 10:22:04 +0000 | [diff] [blame] | 147 | // Extracts the national prefix into national_prefix, or sets it to empty |
| 148 | // string if a national prefix is not present. |
| 149 | void RemoveNationalPrefixFromNationalNumber(string* national_prefix); |
philip.liard@gmail.com | 80d738a | 2011-09-14 10:42:59 +0000 | [diff] [blame] | 150 | |
| 151 | // Extracts IDD and plus sign to prefix_before_national_number_ when they are |
| 152 | // available, and places the remaining input into national_number_. |
| 153 | bool AttemptToExtractIdd(); |
| 154 | |
| 155 | // Extracts country code from the begining of national_number_ to |
| 156 | // prefix_before_national_number_ when they are available, and places the |
| 157 | // remaining input into national_number_. |
| 158 | // Returns true when a valid country code can be found. |
| 159 | bool AttemptToExtractCountryCode(); |
| 160 | |
| 161 | // Accrues digits and the plus sign to accrued_input_without_formatting for |
| 162 | // later use. If next_char contains a digit in non-ASCII format (e.g the |
| 163 | // full-width version of digits), it is first normalized to the ASCII |
| 164 | // version. The return value is next_char itself, or its normalized version, |
| 165 | // if next_char is a digit in non-ASCII format. |
| 166 | char NormalizeAndAccrueDigitsAndPlusSign(char32 next_char, |
| 167 | bool remember_position); |
| 168 | |
| 169 | void InputDigitHelper(char next_char, string* number); |
| 170 | |
| 171 | // Converts UnicodeString position to std::string position. |
| 172 | static int ConvertUnicodeStringPosition(const UnicodeString& s, int pos); |
| 173 | |
| 174 | // Class attributes. |
| 175 | const scoped_ptr<const AbstractRegExpFactory> regexp_factory_; |
| 176 | RegExpCache regexp_cache_; |
| 177 | |
| 178 | string current_output_; |
| 179 | |
| 180 | UnicodeString formatting_template_; |
| 181 | string current_formatting_pattern_; |
| 182 | |
| 183 | UnicodeString accrued_input_; |
| 184 | UnicodeString accrued_input_without_formatting_; |
| 185 | |
philip.liard@gmail.com | 7094201 | 2011-09-16 10:22:04 +0000 | [diff] [blame] | 186 | // This indicates whether AsYouTypeFormatter is currently doing the |
| 187 | // formatting. |
philip.liard@gmail.com | 80d738a | 2011-09-14 10:42:59 +0000 | [diff] [blame] | 188 | bool able_to_format_; |
philip.liard@gmail.com | 7094201 | 2011-09-16 10:22:04 +0000 | [diff] [blame] | 189 | // Set to true when users enter their own formatting. AsYouTypeFormatter will |
| 190 | // do no formatting at all when this is set to true. |
| 191 | bool input_has_formatting_; |
lararennie@google.com | 35bd393 | 2012-09-06 09:48:57 +0000 | [diff] [blame] | 192 | // This is set to true when we know the user is entering a full national |
| 193 | // significant number, since we have either detected a national prefix or an |
| 194 | // international dialing prefix. When this is true, we will no longer use |
| 195 | // local number formatting patterns. |
| 196 | bool is_complete_number_; |
philip.liard@gmail.com | 80d738a | 2011-09-14 10:42:59 +0000 | [diff] [blame] | 197 | bool is_expecting_country_code_; |
| 198 | |
| 199 | const PhoneNumberUtil& phone_util_; |
| 200 | |
| 201 | const string default_country_; |
| 202 | |
| 203 | const PhoneMetadata empty_metadata_; |
| 204 | const PhoneMetadata* const default_metadata_; |
| 205 | const PhoneMetadata* current_metadata_; |
| 206 | |
| 207 | int last_match_position_; |
| 208 | |
| 209 | // The position of a digit upon which InputDigitAndRememberPosition is most |
| 210 | // recently invoked, as found in the original sequence of characters the user |
| 211 | // entered. |
| 212 | int original_position_; |
| 213 | |
| 214 | // The position of a digit upon which InputDigitAndRememberPosition is most |
| 215 | // recently invoked, as found in AccruedInputWithoutFormatting. |
| 216 | int position_to_remember_; |
| 217 | |
philip.liard@gmail.com | 7094201 | 2011-09-16 10:22:04 +0000 | [diff] [blame] | 218 | // This contains anything that has been entered so far preceding the national |
| 219 | // significant number, and it is formatted (e.g. with space inserted). For |
| 220 | // example, this can contain IDD, country code, and/or NDD, etc. |
philip.liard@gmail.com | 80d738a | 2011-09-14 10:42:59 +0000 | [diff] [blame] | 221 | string prefix_before_national_number_; |
lararennie@google.com | 35bd393 | 2012-09-06 09:48:57 +0000 | [diff] [blame] | 222 | bool should_add_space_after_national_prefix_; |
philip.liard@gmail.com | 7094201 | 2011-09-16 10:22:04 +0000 | [diff] [blame] | 223 | // This contains the national prefix that has been extracted. It contains only |
| 224 | // digits without formatting. |
| 225 | string national_prefix_extracted_; |
philip.liard@gmail.com | 80d738a | 2011-09-14 10:42:59 +0000 | [diff] [blame] | 226 | string national_number_; |
| 227 | |
| 228 | list<const NumberFormat*> possible_formats_; |
| 229 | |
| 230 | friend class PhoneNumberUtil; |
| 231 | friend class AsYouTypeFormatterTest; |
| 232 | |
| 233 | // Disallow copy and assign since this class uses RegExpCache which can't be |
| 234 | // copied. |
| 235 | DISALLOW_COPY_AND_ASSIGN(AsYouTypeFormatter); |
| 236 | }; |
| 237 | |
| 238 | } // namespace phonenumbers |
| 239 | } // namespace i18n |
| 240 | |
| 241 | #endif // I18N_PHONENUMBERS_ASYOUTYPEFORMATTER_H_ |