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
46namespace i18n {
47namespace phonenumbers {
48
49using std::list;
50using std::string;
51
52class PhoneNumberUtil;
53
54class 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