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 // 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. 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 39 #include "phonenumbers/base/basictypes.h" 40 #include "phonenumbers/base/memory/scoped_ptr.h" 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 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 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 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 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. 126 void AttemptToFormatAccruedDigits(string* formatted_number); 127 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 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 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 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); 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 186 // This indicates whether AsYouTypeFormatter is currently doing the 187 // formatting. 188 bool able_to_format_; 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_; 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_; 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 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. 221 string prefix_before_national_number_; 222 bool should_add_space_after_national_prefix_; 223 // This contains the national prefix that has been extracted. It contains only 224 // digits without formatting. 225 string national_prefix_extracted_; 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_ 242