• 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:
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