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