Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(624)

Side by Side Diff: chrome/browser/autofill/phone_field.cc

Issue 12434004: Move remaining Autofill code to //components/autofill. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix long lines Created 7 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome/browser/autofill/phone_field.h ('k') | chrome/browser/autofill/phone_field_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/autofill/phone_field.h"
6
7 #include "base/logging.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/string16.h"
10 #include "base/string_util.h"
11 #include "base/utf_string_conversions.h"
12 #include "chrome/browser/autofill/autofill_field.h"
13 #include "chrome/browser/autofill/autofill_regex_constants.h"
14 #include "chrome/browser/autofill/autofill_scanner.h"
15 #include "ui/base/l10n/l10n_util.h"
16
17 namespace {
18
19 // This string includes all area code separators, including NoText.
20 string16 GetAreaRegex() {
21 string16 area_code = UTF8ToUTF16(autofill::kAreaCodeRe);
22 area_code.append(ASCIIToUTF16("|")); // Regexp separator.
23 area_code.append(UTF8ToUTF16(autofill::kAreaCodeNotextRe));
24 return area_code;
25 }
26
27 } // namespace
28
29 PhoneField::~PhoneField() {}
30
31 // Phone field grammars - first matched grammar will be parsed. Grammars are
32 // separated by { REGEX_SEPARATOR, FIELD_NONE, 0 }. Suffix and extension are
33 // parsed separately unless they are necessary parts of the match.
34 // The following notation is used to describe the patterns:
35 // <cc> - country code field.
36 // <ac> - area code field.
37 // <phone> - phone or prefix.
38 // <suffix> - suffix.
39 // <ext> - extension.
40 // :N means field is limited to N characters, otherwise it is unlimited.
41 // (pattern <field>)? means pattern is optional and matched separately.
42 const PhoneField::Parser PhoneField::kPhoneFieldGrammars[] = {
43 // Country code: <cc> Area Code: <ac> Phone: <phone> (- <suffix>
44 // (Ext: <ext>)?)?
45 { REGEX_COUNTRY, FIELD_COUNTRY_CODE, 0 },
46 { REGEX_AREA, FIELD_AREA_CODE, 0 },
47 { REGEX_PHONE, FIELD_PHONE, 0 },
48 { REGEX_SEPARATOR, FIELD_NONE, 0 },
49 // \( <ac> \) <phone>:3 <suffix>:4 (Ext: <ext>)?
50 { REGEX_AREA_NOTEXT, FIELD_AREA_CODE, 3 },
51 { REGEX_PREFIX_SEPARATOR, FIELD_PHONE, 3 },
52 { REGEX_PHONE, FIELD_SUFFIX, 4 },
53 { REGEX_SEPARATOR, FIELD_NONE, 0 },
54 // Phone: <cc> <ac>:3 - <phone>:3 - <suffix>:4 (Ext: <ext>)?
55 { REGEX_PHONE, FIELD_COUNTRY_CODE, 0 },
56 { REGEX_PHONE, FIELD_AREA_CODE, 3 },
57 { REGEX_PREFIX_SEPARATOR, FIELD_PHONE, 3 },
58 { REGEX_SUFFIX_SEPARATOR, FIELD_SUFFIX, 4 },
59 { REGEX_SEPARATOR, FIELD_NONE, 0 },
60 // Phone: <cc>:3 <ac>:3 <phone>:3 <suffix>:4 (Ext: <ext>)?
61 { REGEX_PHONE, FIELD_COUNTRY_CODE, 3 },
62 { REGEX_PHONE, FIELD_AREA_CODE, 3 },
63 { REGEX_PHONE, FIELD_PHONE, 3 },
64 { REGEX_PHONE, FIELD_SUFFIX, 4 },
65 { REGEX_SEPARATOR, FIELD_NONE, 0 },
66 // Area Code: <ac> Phone: <phone> (- <suffix> (Ext: <ext>)?)?
67 { REGEX_AREA, FIELD_AREA_CODE, 0 },
68 { REGEX_PHONE, FIELD_PHONE, 0 },
69 { REGEX_SEPARATOR, FIELD_NONE, 0 },
70 // Phone: <ac> <phone>:3 <suffix>:4 (Ext: <ext>)?
71 { REGEX_PHONE, FIELD_AREA_CODE, 0 },
72 { REGEX_PHONE, FIELD_PHONE, 3 },
73 { REGEX_PHONE, FIELD_SUFFIX, 4 },
74 { REGEX_SEPARATOR, FIELD_NONE, 0 },
75 // Phone: <cc> \( <ac> \) <phone> (- <suffix> (Ext: <ext>)?)?
76 { REGEX_PHONE, FIELD_COUNTRY_CODE, 0 },
77 { REGEX_AREA_NOTEXT, FIELD_AREA_CODE, 0 },
78 { REGEX_PREFIX_SEPARATOR, FIELD_PHONE, 0 },
79 { REGEX_SEPARATOR, FIELD_NONE, 0 },
80 // Phone: \( <ac> \) <phone> (- <suffix> (Ext: <ext>)?)?
81 { REGEX_PHONE, FIELD_COUNTRY_CODE, 0 },
82 { REGEX_AREA_NOTEXT, FIELD_AREA_CODE, 0 },
83 { REGEX_PREFIX_SEPARATOR, FIELD_PHONE, 0 },
84 { REGEX_SEPARATOR, FIELD_NONE, 0 },
85 // Phone: <cc> - <ac> - <phone> - <suffix> (Ext: <ext>)?
86 { REGEX_PHONE, FIELD_COUNTRY_CODE, 0 },
87 { REGEX_PREFIX_SEPARATOR, FIELD_AREA_CODE, 0 },
88 { REGEX_PREFIX_SEPARATOR, FIELD_PHONE, 0 },
89 { REGEX_SUFFIX_SEPARATOR, FIELD_SUFFIX, 0 },
90 { REGEX_SEPARATOR, FIELD_NONE, 0 },
91 // Phone: <ac> Prefix: <phone> Suffix: <suffix> (Ext: <ext>)?
92 { REGEX_PHONE, FIELD_AREA_CODE, 0 },
93 { REGEX_PREFIX, FIELD_PHONE, 0 },
94 { REGEX_SUFFIX, FIELD_SUFFIX, 0 },
95 { REGEX_SEPARATOR, FIELD_NONE, 0 },
96 // Phone: <ac> - <phone>:3 - <suffix>:4 (Ext: <ext>)?
97 { REGEX_PHONE, FIELD_AREA_CODE, 0 },
98 { REGEX_PREFIX_SEPARATOR, FIELD_PHONE, 3 },
99 { REGEX_SUFFIX_SEPARATOR, FIELD_SUFFIX, 4 },
100 { REGEX_SEPARATOR, FIELD_NONE, 0 },
101 // Phone: <cc> - <ac> - <phone> (Ext: <ext>)?
102 { REGEX_PHONE, FIELD_COUNTRY_CODE, 0 },
103 { REGEX_PREFIX_SEPARATOR, FIELD_AREA_CODE, 0 },
104 { REGEX_SUFFIX_SEPARATOR, FIELD_PHONE, 0 },
105 { REGEX_SEPARATOR, FIELD_NONE, 0 },
106 // Phone: <ac> - <phone> (Ext: <ext>)?
107 { REGEX_AREA, FIELD_AREA_CODE, 0 },
108 { REGEX_PHONE, FIELD_PHONE, 0 },
109 { REGEX_SEPARATOR, FIELD_NONE, 0 },
110 // Phone: <cc>:3 - <phone>:10 (Ext: <ext>)?
111 { REGEX_PHONE, FIELD_COUNTRY_CODE, 3 },
112 { REGEX_PHONE, FIELD_PHONE, 10 },
113 { REGEX_SEPARATOR, FIELD_NONE, 0 },
114 // Phone: <phone> (Ext: <ext>)?
115 { REGEX_PHONE, FIELD_PHONE, 0 },
116 { REGEX_SEPARATOR, FIELD_NONE, 0 },
117 };
118
119 // static
120 FormField* PhoneField::Parse(AutofillScanner* scanner) {
121 if (scanner->IsEnd())
122 return NULL;
123
124 scanner->SaveCursor();
125
126 // The form owns the following variables, so they should not be deleted.
127 const AutofillField* parsed_fields[FIELD_MAX];
128
129 for (size_t i = 0; i < arraysize(kPhoneFieldGrammars); ++i) {
130 memset(parsed_fields, 0, sizeof(parsed_fields));
131 scanner->SaveCursor();
132
133 // Attempt to parse according to the next grammar.
134 for (; i < arraysize(kPhoneFieldGrammars) &&
135 kPhoneFieldGrammars[i].regex != REGEX_SEPARATOR; ++i) {
136 if (!ParseFieldSpecifics(
137 scanner,
138 GetRegExp(kPhoneFieldGrammars[i].regex),
139 MATCH_DEFAULT | MATCH_TELEPHONE,
140 &parsed_fields[kPhoneFieldGrammars[i].phone_part]))
141 break;
142 if (kPhoneFieldGrammars[i].max_size &&
143 (!parsed_fields[kPhoneFieldGrammars[i].phone_part]->max_length ||
144 kPhoneFieldGrammars[i].max_size <
145 parsed_fields[kPhoneFieldGrammars[i].phone_part]->max_length)) {
146 break;
147 }
148 }
149
150 if (i >= arraysize(kPhoneFieldGrammars)) {
151 scanner->Rewind();
152 return NULL; // Parsing failed.
153 }
154 if (kPhoneFieldGrammars[i].regex == REGEX_SEPARATOR)
155 break; // Parsing succeeded.
156
157 // Proceed to the next grammar.
158 do {
159 ++i;
160 } while (i < arraysize(kPhoneFieldGrammars) &&
161 kPhoneFieldGrammars[i].regex != REGEX_SEPARATOR);
162
163 if (i + 1 == arraysize(kPhoneFieldGrammars)) {
164 scanner->Rewind();
165 return NULL; // Tried through all the possibilities - did not match.
166 }
167
168 scanner->Rewind();
169 }
170
171 if (!parsed_fields[FIELD_PHONE]) {
172 scanner->Rewind();
173 return NULL;
174 }
175
176 scoped_ptr<PhoneField> phone_field(new PhoneField);
177 for (int i = 0; i < FIELD_MAX; ++i)
178 phone_field->parsed_phone_fields_[i] = parsed_fields[i];
179
180 // Look for optional fields.
181
182 // Look for a third text box.
183 if (!phone_field->parsed_phone_fields_[FIELD_SUFFIX]) {
184 if (!ParseField(scanner, UTF8ToUTF16(autofill::kPhoneSuffixRe),
185 &phone_field->parsed_phone_fields_[FIELD_SUFFIX])) {
186 ParseField(scanner, UTF8ToUTF16(autofill::kPhoneSuffixSeparatorRe),
187 &phone_field->parsed_phone_fields_[FIELD_SUFFIX]);
188 }
189 }
190
191 // Now look for an extension.
192 ParseField(scanner, UTF8ToUTF16(autofill::kPhoneExtensionRe),
193 &phone_field->parsed_phone_fields_[FIELD_EXTENSION]);
194
195 return phone_field.release();
196 }
197
198 bool PhoneField::ClassifyField(FieldTypeMap* map) const {
199 bool ok = true;
200
201 DCHECK(parsed_phone_fields_[FIELD_PHONE]); // Phone was correctly parsed.
202
203 if ((parsed_phone_fields_[FIELD_COUNTRY_CODE] != NULL) ||
204 (parsed_phone_fields_[FIELD_AREA_CODE] != NULL) ||
205 (parsed_phone_fields_[FIELD_SUFFIX] != NULL)) {
206 if (parsed_phone_fields_[FIELD_COUNTRY_CODE] != NULL) {
207 ok = ok && AddClassification(parsed_phone_fields_[FIELD_COUNTRY_CODE],
208 PHONE_HOME_COUNTRY_CODE,
209 map);
210 }
211
212 AutofillFieldType field_number_type = PHONE_HOME_NUMBER;
213 if (parsed_phone_fields_[FIELD_AREA_CODE] != NULL) {
214 ok = ok && AddClassification(parsed_phone_fields_[FIELD_AREA_CODE],
215 PHONE_HOME_CITY_CODE,
216 map);
217 } else if (parsed_phone_fields_[FIELD_COUNTRY_CODE] != NULL) {
218 // Only if we can find country code without city code, it means the phone
219 // number include city code.
220 field_number_type = PHONE_HOME_CITY_AND_NUMBER;
221 }
222 // We tag the prefix as PHONE_HOME_NUMBER, then when filling the form
223 // we fill only the prefix depending on the size of the input field.
224 ok = ok && AddClassification(parsed_phone_fields_[FIELD_PHONE],
225 field_number_type,
226 map);
227 // We tag the suffix as PHONE_HOME_NUMBER, then when filling the form
228 // we fill only the suffix depending on the size of the input field.
229 if (parsed_phone_fields_[FIELD_SUFFIX] != NULL) {
230 ok = ok && AddClassification(parsed_phone_fields_[FIELD_SUFFIX],
231 PHONE_HOME_NUMBER,
232 map);
233 }
234 } else {
235 ok = AddClassification(parsed_phone_fields_[FIELD_PHONE],
236 PHONE_HOME_WHOLE_NUMBER,
237 map);
238 }
239
240 return ok;
241 }
242
243 PhoneField::PhoneField() {
244 memset(parsed_phone_fields_, 0, sizeof(parsed_phone_fields_));
245 }
246
247 // static
248 string16 PhoneField::GetRegExp(RegexType regex_id) {
249 switch (regex_id) {
250 case REGEX_COUNTRY:
251 return UTF8ToUTF16(autofill::kCountryCodeRe);
252 case REGEX_AREA:
253 return GetAreaRegex();
254 case REGEX_AREA_NOTEXT:
255 return UTF8ToUTF16(autofill::kAreaCodeNotextRe);
256 case REGEX_PHONE:
257 return UTF8ToUTF16(autofill::kPhoneRe);
258 case REGEX_PREFIX_SEPARATOR:
259 return UTF8ToUTF16(autofill::kPhonePrefixSeparatorRe);
260 case REGEX_PREFIX:
261 return UTF8ToUTF16(autofill::kPhonePrefixRe);
262 case REGEX_SUFFIX_SEPARATOR:
263 return UTF8ToUTF16(autofill::kPhoneSuffixSeparatorRe);
264 case REGEX_SUFFIX:
265 return UTF8ToUTF16(autofill::kPhoneSuffixRe);
266 case REGEX_EXTENSION:
267 return UTF8ToUTF16(autofill::kPhoneExtensionRe);
268 default:
269 NOTREACHED();
270 break;
271 }
272 return string16();
273 }
OLDNEW
« no previous file with comments | « chrome/browser/autofill/phone_field.h ('k') | chrome/browser/autofill/phone_field_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698