summaryrefslogtreecommitdiff
path: root/asyoutypeformatter.h
blob: e1f850b8dba478bee12ecc88ecf95b066e839eaa (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
// Copyright (C) 2011 The Libphonenumber Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// A formatter which formats phone numbers as they are entered.
//
// An AsYouTypeFormatter can be created by invoking the GetAsYouTypeFormatter
// method of the PhoneNumberUtil. After that digits can be added by invoking the
// InputDigit method on the formatter instance, and the partially formatted
// phone number will be returned each time a digit is added. The Clear method
// can be invoked before a new number needs to be formatted.
//
// See AYTF_US, AYTF_GBFixedLine and AYTF_DE test functions in
// asyoutypeformatter_test.cc for more details on how the formatter is to be
// used.
//
// This is a direct port from AsYouTypeFormatter.java.
// Changes to this class should also happen to the Java version, whenever it
// makes sense.
//
// This class is NOT THREAD SAFE.

#ifndef I18N_PHONENUMBERS_ASYOUTYPEFORMATTER_H_
#define I18N_PHONENUMBERS_ASYOUTYPEFORMATTER_H_

#include <list>
#include <string>

#include "phonenumbers/base/basictypes.h"
#include "phonenumbers/base/memory/scoped_ptr.h"
#include "phonenumbers/regexp_adapter.h"
#include "phonenumbers/regexp_cache.h"
#include "phonenumbers/phonemetadata.pb.h"
#include "phonenumbers/unicodestring.h"

namespace i18n {
namespace phonenumbers {

using std::list;
using std::string;

class PhoneNumberUtil;

class AsYouTypeFormatter {
 public:
  ~AsYouTypeFormatter() {}

  // Formats a phone number on-the-fly as each digit is entered.
  // next_char is the most recently entered digit of a phone number. Formatting
  // characters are allowed, but as soon as they are encountered this method
  // formats the number as entered and not "as you type" anymore. Full width
  // digits and Arabic-indic digits are allowed, and will be shown as they are.
  // Returns the partially formatted phone number (which is a reference to the
  // given string parameter for convenience).
  const string& InputDigit(char32 next_char, string* result);

  // Same as InputDigit, but remembers the position where next_char is inserted,
  // so that it could be retrieved later by using GetRememberedPosition(). The
  // remembered position will be automatically adjusted if additional formatting
  // characters are later inserted/removed in front of next_char.
  // Returns the partially formatted phone number (which is a reference to the
  // given string parameter for convenience).
  const string& InputDigitAndRememberPosition(char32 next_char, string* result);

  // Returns the current position in the partially formatted phone number of the
  // character which was previously passed in as the parameter of
  // InputDigitAndRememberPosition().
  int GetRememberedPosition() const;

  // Clears the internal state of the formatter, so it could be reused.
  void Clear();

 private:
  // Constructs an as-you-type formatter. Should be obtained from
  // PhoneNumberUtil::GetAsYouTypeFormatter().
  explicit AsYouTypeFormatter(const string& region_code);

  // Returns the metadata corresponding to the given region code or empty
  // metadata if it is unsupported.
  const PhoneMetadata* GetMetadataForRegion(const string& region_code) const;

  // Returns true if a new template is created as opposed to reusing the
  // existing template.
  bool MaybeCreateNewTemplate();

  void GetAvailableFormats(const string& leading_three_digits);

  void NarrowDownPossibleFormats(const string& leading_digits);

  // Calculates whether we should be adding a space after the national prefix
  // for this formatting rule or not.
  void SetShouldAddSpaceAfterNationalPrefix(const NumberFormat& format);

  bool CreateFormattingTemplate(const NumberFormat& format);

  // Gets a formatting template which could be used to efficiently format a
  // partial number where digits are added one by one.
  void GetFormattingTemplate(const string& number_pattern,
                             const string& number_format,
                             UnicodeString* formatting_template);

  void InputDigitWithOptionToRememberPosition(char32 next_char,
                                              bool remember_position,
                                              string* phone_number);

  void AttemptToChoosePatternWithPrefixExtracted(string* formatted_number);

  // Some national prefixes are a substring of others. If extracting the
  // shorter NDD doesn't result in a number we can format, we try to see if we
  // can extract a longer version here.
  bool AbleToExtractLongerNdd();

  // Check to see if there is an exact pattern match for these digits. If so, we
  // should use this instead of any other formatting template whose
  // leadingDigitsPattern also matches the input.
  void AttemptToFormatAccruedDigits(string* formatted_number);

  // Combines the national number with any prefix (IDD/+ and country code or
  // national prefix) that was collected. A space will be inserted between them
  // if the current formatting template indicates this to be suitable.
  // The result will be stored in phone_number.
  void AppendNationalNumber(const string& national_number,
                            string* phone_number) const;

  // Attempts to set the formatting template and assigns the passed-in string
  // parameter to the formatted version of the digits entered so far.
  void AttemptToChooseFormattingPattern(string* formatted_number);

  // Invokes InputDigitHelper on each digit of the national number accrued, and
  // assigns the passed-in string parameter to a formatted string in the end.
  void InputAccruedNationalNumber(string* number);

  // Returns true if the current country is a NANPA country and the national
  // number begins with the national prefix.
  bool IsNanpaNumberWithNationalPrefix() const;

  // Extracts the national prefix into national_prefix, or sets it to empty
  // string if a national prefix is not present.
  void RemoveNationalPrefixFromNationalNumber(string* national_prefix);

  // Extracts IDD and plus sign to prefix_before_national_number_ when they are
  // available, and places the remaining input into national_number_.
  bool AttemptToExtractIdd();

  // Extracts country code from the begining of national_number_ to
  // prefix_before_national_number_ when they are available, and places the
  // remaining input into national_number_.
  // Returns true when a valid country code can be found.
  bool AttemptToExtractCountryCode();

  // Accrues digits and the plus sign to accrued_input_without_formatting for
  // later use. If next_char contains a digit in non-ASCII format (e.g the
  // full-width version of digits), it is first normalized to the ASCII
  // version. The return value is next_char itself, or its normalized version,
  // if next_char is a digit in non-ASCII format.
  char NormalizeAndAccrueDigitsAndPlusSign(char32 next_char,
                                           bool remember_position);

  void InputDigitHelper(char next_char, string* number);

  // Converts UnicodeString position to std::string position.
  static int ConvertUnicodeStringPosition(const UnicodeString& s, int pos);

  // Class attributes.
  const scoped_ptr<const AbstractRegExpFactory> regexp_factory_;
  RegExpCache regexp_cache_;

  string current_output_;

  UnicodeString formatting_template_;
  string current_formatting_pattern_;

  UnicodeString accrued_input_;
  UnicodeString accrued_input_without_formatting_;

  // This indicates whether AsYouTypeFormatter is currently doing the
  // formatting.
  bool able_to_format_;
  // Set to true when users enter their own formatting. AsYouTypeFormatter will
  // do no formatting at all when this is set to true.
  bool input_has_formatting_;
  // This is set to true when we know the user is entering a full national
  // significant number, since we have either detected a national prefix or an
  // international dialing prefix. When this is true, we will no longer use
  // local number formatting patterns.
  bool is_complete_number_;
  bool is_expecting_country_code_;

  const PhoneNumberUtil& phone_util_;

  const string default_country_;

  const PhoneMetadata empty_metadata_;
  const PhoneMetadata* const default_metadata_;
  const PhoneMetadata* current_metadata_;

  int last_match_position_;

  // The position of a digit upon which InputDigitAndRememberPosition is most
  // recently invoked, as found in the original sequence of characters the user
  // entered.
  int original_position_;

  // The position of a digit upon which InputDigitAndRememberPosition is most
  // recently invoked, as found in AccruedInputWithoutFormatting.
  int position_to_remember_;

  // This contains anything that has been entered so far preceding the national
  // significant number, and it is formatted (e.g. with space inserted). For
  // example, this can contain IDD, country code, and/or NDD, etc.
  string prefix_before_national_number_;
  bool should_add_space_after_national_prefix_;
  // This contains the national prefix that has been extracted. It contains only
  // digits without formatting.
  string national_prefix_extracted_;
  string national_number_;

  list<const NumberFormat*> possible_formats_;

  friend class PhoneNumberUtil;
  friend class AsYouTypeFormatterTest;

  // Disallow copy and assign since this class uses RegExpCache which can't be
  // copied.
  DISALLOW_COPY_AND_ASSIGN(AsYouTypeFormatter);
};

}  // namespace phonenumbers
}  // namespace i18n

#endif  // I18N_PHONENUMBERS_ASYOUTYPEFORMATTER_H_