blob: e1f850b8dba478bee12ecc88ecf95b066e839eaa [file] [log] [blame]
philip.liard@gmail.com80d738a2011-09-14 10:42:59 +00001// 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//
lararennie@google.com35bd3932012-09-06 09:48:57 +000027// 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.
philip.liard@gmail.com80d738a2011-09-14 10:42:59 +000030//
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
philip.liard@gmail.comaf4a2ce2013-04-30 11:35:55 +000039#include "phonenumbers/base/basictypes.h"
40#include "phonenumbers/base/memory/scoped_ptr.h"
philip.liard@gmail.com80d738a2011-09-14 10:42:59 +000041#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
lararennie@google.com35bd3932012-09-06 09:48:57 +0000100 // 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
philip.liard@gmail.com80d738a2011-09-14 10:42:59 +0000104 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
philip.liard@gmail.com70942012011-09-16 10:22:04 +0000116 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
lararennie@google.com35bd3932012-09-06 09:48:57 +0000123 // 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.
philip.liard@gmail.com80d738a2011-09-14 10:42:59 +0000126 void AttemptToFormatAccruedDigits(string* formatted_number);
127
lararennie@google.com35bd3932012-09-06 09:48:57 +0000128 // 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
philip.liard@gmail.com80d738a2011-09-14 10:42:59 +0000135 // 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
lararennie@google.com35bd3932012-09-06 09:48:57 +0000143 // 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
philip.liard@gmail.com70942012011-09-16 10:22:04 +0000147 // 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);
philip.liard@gmail.com80d738a2011-09-14 10:42:59 +0000150
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
philip.liard@gmail.com70942012011-09-16 10:22:04 +0000186 // This indicates whether AsYouTypeFormatter is currently doing the
187 // formatting.
philip.liard@gmail.com80d738a2011-09-14 10:42:59 +0000188 bool able_to_format_;
philip.liard@gmail.com70942012011-09-16 10:22:04 +0000189 // 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_;
lararennie@google.com35bd3932012-09-06 09:48:57 +0000192 // 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_;
philip.liard@gmail.com80d738a2011-09-14 10:42:59 +0000197 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
philip.liard@gmail.com70942012011-09-16 10:22:04 +0000218 // 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.
philip.liard@gmail.com80d738a2011-09-14 10:42:59 +0000221 string prefix_before_national_number_;
lararennie@google.com35bd3932012-09-06 09:48:57 +0000222 bool should_add_space_after_national_prefix_;
philip.liard@gmail.com70942012011-09-16 10:22:04 +0000223 // This contains the national prefix that has been extracted. It contains only
224 // digits without formatting.
225 string national_prefix_extracted_;
philip.liard@gmail.com80d738a2011-09-14 10:42:59 +0000226 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_