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 51 class PhoneNumberUtil; 52 53 class AsYouTypeFormatter { 54 public: 55 56 // This type is neither copyable nor movable. 57 AsYouTypeFormatter(const AsYouTypeFormatter&) = delete; 58 AsYouTypeFormatter& operator=(const AsYouTypeFormatter&) = delete; 59 ~AsYouTypeFormatter()60 ~AsYouTypeFormatter() {} 61 62 // Formats a phone number on-the-fly as each digit is entered. 63 // next_char is the most recently entered digit of a phone number. Formatting 64 // characters are allowed, but as soon as they are encountered this method 65 // formats the number as entered and not "as you type" anymore. Full width 66 // digits and Arabic-indic digits are allowed, and will be shown as they are. 67 // Returns the partially formatted phone number (which is a reference to the 68 // given string parameter for convenience). 69 const string& InputDigit(char32 next_char, string* result); 70 71 // Same as InputDigit, but remembers the position where next_char is inserted, 72 // so that it could be retrieved later by using GetRememberedPosition(). The 73 // remembered position will be automatically adjusted if additional formatting 74 // characters are later inserted/removed in front of next_char. 75 // Returns the partially formatted phone number (which is a reference to the 76 // given string parameter for convenience). 77 const string& InputDigitAndRememberPosition(char32 next_char, string* result); 78 79 // Returns the current position in the partially formatted phone number of the 80 // character which was previously passed in as the parameter of 81 // InputDigitAndRememberPosition(). 82 int GetRememberedPosition() const; 83 84 // Clears the internal state of the formatter, so it could be reused. 85 void Clear(); 86 87 private: 88 // Constructs an as-you-type formatter. Should be obtained from 89 // PhoneNumberUtil::GetAsYouTypeFormatter(). 90 explicit AsYouTypeFormatter(const string& region_code); 91 92 // Returns the metadata corresponding to the given region code or empty 93 // metadata if it is unsupported. 94 const PhoneMetadata* GetMetadataForRegion(const string& region_code) const; 95 96 // Returns true if a new template is created as opposed to reusing the 97 // existing template. 98 bool MaybeCreateNewTemplate(); 99 100 void GetAvailableFormats(const string& leading_digits); 101 102 void NarrowDownPossibleFormats(const string& leading_digits); 103 104 // Calculates whether we should be adding a space after the national prefix 105 // for this formatting rule or not. 106 void SetShouldAddSpaceAfterNationalPrefix(const NumberFormat& format); 107 108 bool CreateFormattingTemplate(const NumberFormat& format); 109 110 // Gets a formatting template which could be used to efficiently format a 111 // partial number where digits are added one by one. 112 void GetFormattingTemplate(const string& number_pattern, 113 const string& number_format, 114 UnicodeString* formatting_template); 115 116 void InputDigitWithOptionToRememberPosition(char32 next_char, 117 bool remember_position, 118 string* phone_number); 119 120 void AttemptToChoosePatternWithPrefixExtracted(string* formatted_number); 121 122 const string& GetExtractedNationalPrefix() const; 123 124 // Some national prefixes are a substring of others. If extracting the 125 // shorter NDD doesn't result in a number we can format, we try to see if we 126 // can extract a longer version here. 127 bool AbleToExtractLongerNdd(); 128 129 // Check to see if there is an exact pattern match for these digits. If so, we 130 // should use this instead of any other formatting template whose 131 // leadingDigitsPattern also matches the input. 132 void AttemptToFormatAccruedDigits(string* formatted_number); 133 134 // Combines the national number with any prefix (IDD/+ and country code or 135 // national prefix) that was collected. A space will be inserted between them 136 // if the current formatting template indicates this to be suitable. 137 // The result will be stored in phone_number. 138 void AppendNationalNumber(const string& national_number, 139 string* phone_number) const; 140 141 // Attempts to set the formatting template and assigns the passed-in string 142 // parameter to the formatted version of the digits entered so far. 143 void AttemptToChooseFormattingPattern(string* formatted_number); 144 145 // Invokes InputDigitHelper on each digit of the national number accrued, and 146 // assigns the passed-in string parameter to a formatted string in the end. 147 void InputAccruedNationalNumber(string* number); 148 149 // Returns true if the current country is a NANPA country and the national 150 // number begins with the national prefix. 151 bool IsNanpaNumberWithNationalPrefix() const; 152 153 // Extracts the national prefix into national_prefix, or sets it to empty 154 // string if a national prefix is not present. 155 void RemoveNationalPrefixFromNationalNumber(string* national_prefix); 156 157 // Extracts IDD and plus sign to prefix_before_national_number_ when they are 158 // available, and places the remaining input into national_number_. 159 bool AttemptToExtractIdd(); 160 161 // Extracts country code from the begining of national_number_ to 162 // prefix_before_national_number_ when they are available, and places the 163 // remaining input into national_number_. 164 // Returns true when a valid country code can be found. 165 bool AttemptToExtractCountryCode(); 166 167 // Accrues digits and the plus sign to accrued_input_without_formatting for 168 // later use. If next_char contains a digit in non-ASCII format (e.g the 169 // full-width version of digits), it is first normalized to the ASCII 170 // version. The return value is next_char itself, or its normalized version, 171 // if next_char is a digit in non-ASCII format. 172 char NormalizeAndAccrueDigitsAndPlusSign(char32 next_char, 173 bool remember_position); 174 175 void InputDigitHelper(char next_char, string* number); 176 177 // Converts UnicodeString position to std::string position. 178 static int ConvertUnicodeStringPosition(const UnicodeString& s, int pos); 179 180 // Class attributes. 181 const scoped_ptr<const AbstractRegExpFactory> regexp_factory_; 182 RegExpCache regexp_cache_; 183 184 string current_output_; 185 186 UnicodeString formatting_template_; 187 string current_formatting_pattern_; 188 189 UnicodeString accrued_input_; 190 UnicodeString accrued_input_without_formatting_; 191 192 // This indicates whether AsYouTypeFormatter is currently doing the 193 // formatting. 194 bool able_to_format_; 195 // Set to true when users enter their own formatting. AsYouTypeFormatter will 196 // do no formatting at all when this is set to true. 197 bool input_has_formatting_; 198 // This is set to true when we know the user is entering a full national 199 // significant number, since we have either detected a national prefix or an 200 // international dialing prefix. When this is true, we will no longer use 201 // local number formatting patterns. 202 bool is_complete_number_; 203 bool is_expecting_country_code_; 204 205 const PhoneNumberUtil& phone_util_; 206 207 const string default_country_; 208 209 const PhoneMetadata empty_metadata_; 210 const PhoneMetadata* const default_metadata_; 211 const PhoneMetadata* current_metadata_; 212 213 int last_match_position_; 214 215 // The position of a digit upon which InputDigitAndRememberPosition is most 216 // recently invoked, as found in the original sequence of characters the user 217 // entered. 218 int original_position_; 219 220 // The position of a digit upon which InputDigitAndRememberPosition is most 221 // recently invoked, as found in AccruedInputWithoutFormatting. 222 int position_to_remember_; 223 224 // This contains anything that has been entered so far preceding the national 225 // significant number, and it is formatted (e.g. with space inserted). For 226 // example, this can contain IDD, country code, and/or NDD, etc. 227 string prefix_before_national_number_; 228 bool should_add_space_after_national_prefix_; 229 // This contains the national prefix that has been extracted. It contains only 230 // digits without formatting. 231 string extracted_national_prefix_; 232 string national_number_; 233 234 list<const NumberFormat*> possible_formats_; 235 236 friend class PhoneNumberUtil; 237 friend class AsYouTypeFormatterTest; 238 239 // Disallow copy and assign since this class uses RegExpCache which can't be 240 // copied. 241 242 }; 243 244 } // namespace phonenumbers 245 } // namespace i18n 246 247 #endif // I18N_PHONENUMBERS_ASYOUTYPEFORMATTER_H_ 248