• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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