OLD | NEW |
---|---|
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/autofill/phone_field.h" | 5 #include "chrome/browser/autofill/phone_field.h" |
6 | 6 |
7 #include "base/logging.h" | 7 #include "base/logging.h" |
8 #include "base/scoped_ptr.h" | 8 #include "base/scoped_ptr.h" |
9 #include "base/string16.h" | 9 #include "base/string16.h" |
10 #include "base/string_util.h" | 10 #include "base/string_util.h" |
11 #include "base/utf_string_conversions.h" | 11 #include "base/utf_string_conversions.h" |
12 #include "chrome/browser/autofill/autofill_field.h" | 12 #include "chrome/browser/autofill/autofill_field.h" |
13 #include "chrome/browser/autofill/fax_number.h" | 13 #include "chrome/browser/autofill/fax_number.h" |
14 #include "chrome/browser/autofill/home_phone_number.h" | 14 #include "chrome/browser/autofill/home_phone_number.h" |
15 #include "grit/autofill_resources.h" | 15 #include "grit/autofill_resources.h" |
16 #include "ui/base/l10n/l10n_util.h" | 16 #include "ui/base/l10n/l10n_util.h" |
17 | 17 |
18 // Phone field grammars - first matched grammar will be parsed. Grammars are | |
19 // separated by { REGEX_SEPARATOR, FIELD_NONE, 0 }. Suffix and extension are | |
20 // parsed separately unless they are necessary part of the match. | |
Ilya Sherman
2011/02/16 23:22:08
nit: part -> parts
GeorgeY
2011/02/17 00:21:18
Done.
| |
21 // The following comment are indicating the matched pattern: | |
Ilya Sherman
2011/02/16 23:22:08
nit: Perhaps: "The following notation is used to d
GeorgeY
2011/02/17 00:21:18
Done.
| |
22 // <cc> - country code field. | |
23 // <ac> - area code field. | |
24 // <phone> - phone or prefix. | |
25 // <suffix> - suffix. | |
26 // <ext> - extension. | |
27 // :N means field is limited to N characters, otherwise it is unlimited. | |
28 // (pattern <field>)? means patter is optional and matche d separately. | |
Ilya Sherman
2011/02/16 23:22:08
nit: patter -> pattern, matche d -> matched
GeorgeY
2011/02/17 00:21:18
Done.
| |
29 PhoneField::Parser PhoneField::phone_field_grammars_[] = { | |
30 // Country code: <cc> Area Code: <ac> Phone: <phone> (- <suffix> | |
31 // (Ext: <ext>)?)? | |
32 { PhoneField::REGEX_COUNTRY, PhoneField::FIELD_COUNTRY_CODE, 0 }, | |
33 { PhoneField::REGEX_AREA, PhoneField::FIELD_AREA_CODE, 0 }, | |
34 { PhoneField::REGEX_PHONE, PhoneField::FIELD_PHONE, 0 }, | |
35 { PhoneField::REGEX_SEPARATOR, FIELD_NONE, 0 }, | |
36 // Phone: <cc> <ac>:3 - <phone>:3 - <suffix>:4 (Ext: <ext>)? | |
37 { PhoneField::REGEX_PHONE, PhoneField::FIELD_COUNTRY_CODE, 0 }, | |
38 { PhoneField::REGEX_PHONE, PhoneField::FIELD_AREA_CODE, 3 }, | |
39 { PhoneField::REGEX_PREFIX_SEPARATOR, PhoneField::FIELD_PHONE, 3 }, | |
40 { PhoneField::REGEX_SUFFIX_SEPARATOR, PhoneField::FIELD_SUFFIX, 4 }, | |
41 { PhoneField::REGEX_SEPARATOR, FIELD_NONE, 0 }, | |
42 // Phone: <cc>:3 <ac>:3 <phone>:3 <suffix>:4 (Ext: <ext>)? | |
43 { PhoneField::REGEX_PHONE, PhoneField::FIELD_COUNTRY_CODE, 3 }, | |
44 { PhoneField::REGEX_PHONE, PhoneField::FIELD_AREA_CODE, 3 }, | |
45 { PhoneField::REGEX_PHONE, PhoneField::FIELD_PHONE, 3 }, | |
46 { PhoneField::REGEX_PHONE, PhoneField::FIELD_SUFFIX, 4 }, | |
47 { PhoneField::REGEX_SEPARATOR, FIELD_NONE, 0 }, | |
48 // Area Code: <ac> Phone: <phone> (- <suffix> (Ext: <ext>)?)? | |
49 { PhoneField::REGEX_AREA, PhoneField::FIELD_AREA_CODE, 0 }, | |
50 { PhoneField::REGEX_PHONE, PhoneField::FIELD_PHONE, 0 }, | |
51 { PhoneField::REGEX_SEPARATOR, FIELD_NONE, 0 }, | |
52 // Phone: <ac> <phone>:3 <suffix>:4 (Ext: <ext>)? | |
53 { PhoneField::REGEX_PHONE, PhoneField::FIELD_AREA_CODE, 0 }, | |
54 { PhoneField::REGEX_PHONE, PhoneField::FIELD_PHONE, 3 }, | |
55 { PhoneField::REGEX_PHONE, PhoneField::FIELD_SUFFIX, 4 }, | |
56 { PhoneField::REGEX_SEPARATOR, FIELD_NONE, 0 }, | |
57 // Phone: <cc> \( <ac> \) <phone> (- <suffix> (Ext: <ext>)?)? | |
58 { PhoneField::REGEX_PHONE, PhoneField::FIELD_COUNTRY_CODE, 0 }, | |
59 { PhoneField::REGEX_AREA_NOTEXT, PhoneField::FIELD_AREA_CODE, 0 }, | |
60 { PhoneField::REGEX_PREFIX_SEPARATOR, PhoneField::FIELD_PHONE, 0 }, | |
61 { PhoneField::REGEX_SEPARATOR, FIELD_NONE, 0 }, | |
62 // Phone: \( <ac> \) <phone> (- <suffix> (Ext: <ext>)?)? | |
63 { PhoneField::REGEX_PHONE, PhoneField::FIELD_COUNTRY_CODE, 0 }, | |
64 { PhoneField::REGEX_AREA_NOTEXT, PhoneField::FIELD_AREA_CODE, 0 }, | |
65 { PhoneField::REGEX_PREFIX_SEPARATOR, PhoneField::FIELD_PHONE, 0 }, | |
66 { PhoneField::REGEX_SEPARATOR, FIELD_NONE, 0 }, | |
67 // Phone: <cc> - <ac> - <phone> - <suffix> (Ext: <ext>)? | |
68 { PhoneField::REGEX_PHONE, PhoneField::FIELD_COUNTRY_CODE, 0 }, | |
69 { PhoneField::REGEX_PREFIX_SEPARATOR, PhoneField::FIELD_AREA_CODE, 0 }, | |
70 { PhoneField::REGEX_PREFIX_SEPARATOR, PhoneField::FIELD_PHONE, 0 }, | |
71 { PhoneField::REGEX_SUFFIX_SEPARATOR, PhoneField::FIELD_SUFFIX, 0 }, | |
72 { PhoneField::REGEX_SEPARATOR, FIELD_NONE, 0 }, | |
73 // Phone: <ac> Prefix: <phone> Suffix: <suffix> (Ext: <ext>)? | |
74 { PhoneField::REGEX_PHONE, PhoneField::FIELD_AREA_CODE, 0 }, | |
75 { PhoneField::REGEX_PREFIX, PhoneField::FIELD_PHONE, 0 }, | |
76 { PhoneField::REGEX_SUFFIX, PhoneField::FIELD_SUFFIX, 0 }, | |
77 { PhoneField::REGEX_SEPARATOR, FIELD_NONE, 0 }, | |
78 // Phone: <ac> - <phone>:3 - <suffix>:4 (Ext: <ext>)? | |
79 { PhoneField::REGEX_PHONE, PhoneField::FIELD_AREA_CODE, 0 }, | |
80 { PhoneField::REGEX_PREFIX_SEPARATOR, PhoneField::FIELD_PHONE, 3 }, | |
81 { PhoneField::REGEX_SUFFIX_SEPARATOR, PhoneField::FIELD_SUFFIX, 4 }, | |
82 { PhoneField::REGEX_SEPARATOR, FIELD_NONE, 0 }, | |
83 // Phone: <cc> - <ac> - <phone> (Ext: <ext>)? | |
84 { PhoneField::REGEX_PHONE, PhoneField::FIELD_COUNTRY_CODE, 0 }, | |
85 { PhoneField::REGEX_PREFIX_SEPARATOR, PhoneField::FIELD_AREA_CODE, 0 }, | |
86 { PhoneField::REGEX_SUFFIX_SEPARATOR, PhoneField::FIELD_PHONE, 0 }, | |
87 { PhoneField::REGEX_SEPARATOR, FIELD_NONE, 0 }, | |
88 // Phone: <ac> - <phone> (Ext: <ext>)? | |
89 { PhoneField::REGEX_AREA, PhoneField::FIELD_AREA_CODE, 0 }, | |
90 { PhoneField::REGEX_PHONE, PhoneField::FIELD_PHONE, 0 }, | |
91 { PhoneField::REGEX_SEPARATOR, FIELD_NONE, 0 }, | |
92 // Phone: <phone> (Ext: <ext>)? | |
93 { PhoneField::REGEX_PHONE, PhoneField::FIELD_PHONE, 0 }, | |
94 { PhoneField::REGEX_SEPARATOR, FIELD_NONE, 0 }, | |
95 }; | |
96 | |
18 // static | 97 // static |
19 PhoneField* PhoneField::Parse(std::vector<AutoFillField*>::const_iterator* iter, | 98 PhoneField* PhoneField::Parse(std::vector<AutoFillField*>::const_iterator* iter, |
20 bool is_ecml) { | 99 bool is_ecml) { |
21 DCHECK(iter); | 100 DCHECK(iter); |
22 if (!iter) | 101 if (!iter) |
23 return NULL; | 102 return NULL; |
24 | 103 |
25 if (is_ecml) | 104 if (is_ecml) |
26 return ParseECML(iter); | 105 return ParseECML(iter); |
27 | 106 |
28 scoped_ptr<PhoneField> phone_field(new PhoneField); | 107 scoped_ptr<PhoneField> phone_field(new PhoneField); |
29 | 108 |
30 // Go through the phones in order HOME, FAX, attempting to match. HOME should | 109 // Go through the phones in order HOME, FAX, attempting to match. HOME should |
31 // be the last as it is a catch all case ("fax" and "faxarea" parsed as FAX, | 110 // be the last as it is a catch all case ("fax" and "faxarea" parsed as FAX, |
32 // but "area" and "someotherarea" parsed as HOME, for example). | 111 // but "area" and "someotherarea" parsed as HOME, for example). |
33 for (int i = PHONE_TYPE_MAX - 1; i >= PHONE_TYPE_FIRST; --i) { | 112 for (int i = PHONE_TYPE_MAX - 1; i >= PHONE_TYPE_FIRST; --i) { |
34 phone_field->SetPhoneType(static_cast<PhoneField::PHONE_TYPE>(i)); | 113 phone_field->SetPhoneType(static_cast<PhoneField::PhoneType>(i)); |
35 if (ParseInternal(phone_field.get(), iter, i == HOME_PHONE)) | 114 if (ParseInternal(phone_field.get(), iter, i == HOME_PHONE)) |
36 return phone_field.release(); | 115 return phone_field.release(); |
37 } | 116 } |
38 | 117 |
39 return NULL; | 118 return NULL; |
40 } | 119 } |
41 | 120 |
42 // static | 121 // static |
43 PhoneField* PhoneField::ParseECML( | 122 PhoneField* PhoneField::ParseECML( |
44 std::vector<AutoFillField*>::const_iterator* iter) { | 123 std::vector<AutoFillField*>::const_iterator* iter) { |
45 string16 pattern(GetEcmlPattern(kEcmlShipToPhone, kEcmlBillToPhone, '|')); | 124 string16 pattern(GetEcmlPattern(kEcmlShipToPhone, kEcmlBillToPhone, '|')); |
46 | 125 |
47 AutoFillField* field; | 126 AutoFillField* field; |
48 if (ParseText(iter, pattern, &field)) { | 127 if (ParseText(iter, pattern, &field)) { |
49 PhoneField* phone_field = new PhoneField(); | 128 PhoneField* phone_field = new PhoneField(); |
50 phone_field->phone_ = field; | 129 phone_field->parsed_phone_fields_[FIELD_PHONE] = field; |
51 return phone_field; | 130 return phone_field; |
52 } | 131 } |
53 | 132 |
54 return NULL; | 133 return NULL; |
55 } | 134 } |
56 | 135 |
57 bool PhoneField::GetFieldInfo(FieldTypeMap* field_type_map) const { | 136 bool PhoneField::GetFieldInfo(FieldTypeMap* field_type_map) const { |
58 bool ok; | 137 bool ok = false; |
59 | 138 |
60 if (area_code_ != NULL) { | 139 DCHECK(parsed_phone_fields_[FIELD_PHONE]); // Phone was correctly parsed. |
61 ok = Add(field_type_map, area_code_, | 140 |
62 AutoFillType(number_->GetCityCodeType())); | 141 if ((parsed_phone_fields_[FIELD_COUNTRY_CODE] != NULL) || |
142 (parsed_phone_fields_[FIELD_AREA_CODE] != NULL) || | |
143 (parsed_phone_fields_[FIELD_SUFFIX] != NULL)) { | |
144 if (parsed_phone_fields_[FIELD_COUNTRY_CODE] != NULL) { | |
145 ok = Add(field_type_map, | |
146 parsed_phone_fields_[FIELD_COUNTRY_CODE], | |
147 AutoFillType(number_->GetCountryCodeType())); | |
148 DCHECK(ok); | |
149 } | |
150 if (parsed_phone_fields_[FIELD_AREA_CODE] != NULL) { | |
151 ok = Add(field_type_map, | |
152 parsed_phone_fields_[FIELD_AREA_CODE], | |
153 AutoFillType(number_->GetCityCodeType())); | |
154 DCHECK(ok); | |
155 } | |
156 // We tag the prefix as PHONE_HOME_NUMBER, then when filling the form | |
157 // we fill only the prefix depending on the size of the input field. | |
158 ok = Add(field_type_map, | |
159 parsed_phone_fields_[FIELD_PHONE], | |
160 AutoFillType(number_->GetNumberType())); | |
63 DCHECK(ok); | 161 DCHECK(ok); |
64 | 162 // We tag the suffix as PHONE_HOME_NUMBER, then when filling the form |
65 if (prefix_ != NULL) { | 163 // we fill only the suffix depending on the size of the input field. |
66 // We tag the prefix as PHONE_HOME_NUMBER, then when filling the form | 164 if (parsed_phone_fields_[FIELD_SUFFIX] != NULL) { |
67 // we fill only the prefix depending on the size of the input field. | 165 ok = Add(field_type_map, |
68 ok = ok && Add(field_type_map, | 166 parsed_phone_fields_[FIELD_SUFFIX], |
69 prefix_, | 167 AutoFillType(number_->GetNumberType())); |
70 AutoFillType(number_->GetNumberType())); | |
71 DCHECK(ok); | |
72 // We tag the suffix as PHONE_HOME_NUMBER, then when filling the form | |
73 // we fill only the suffix depending on the size of the input field. | |
74 ok = ok && Add(field_type_map, | |
75 phone_, | |
76 AutoFillType(number_->GetNumberType())); | |
77 DCHECK(ok); | |
78 } else { | |
79 ok = ok && Add(field_type_map, | |
80 phone_, | |
81 AutoFillType(number_->GetNumberType())); | |
82 DCHECK(ok); | 168 DCHECK(ok); |
83 } | 169 } |
84 } else { | 170 } else { |
85 ok = Add(field_type_map, | 171 ok = Add(field_type_map, |
86 phone_, | 172 parsed_phone_fields_[FIELD_PHONE], |
87 AutoFillType(number_->GetWholeNumberType())); | 173 AutoFillType(number_->GetWholeNumberType())); |
88 DCHECK(ok); | 174 DCHECK(ok); |
89 } | 175 } |
90 | 176 |
91 return ok; | 177 return ok; |
92 } | 178 } |
93 | 179 |
94 PhoneField::PhoneField() | 180 PhoneField::PhoneField() { |
95 : phone_(NULL), | 181 memset(parsed_phone_fields_, 0, sizeof(parsed_phone_fields_)); |
96 area_code_(NULL), | |
97 prefix_(NULL), | |
98 extension_(NULL) { | |
99 SetPhoneType(HOME_PHONE); | 182 SetPhoneType(HOME_PHONE); |
100 } | 183 } |
101 | 184 |
185 string16 PhoneField::GetCountryRegex() const { | |
186 // This one is the same for Home and Fax numbers. | |
187 return l10n_util::GetStringUTF16(IDS_AUTOFILL_COUNTRY_CODE_RE); | |
188 } | |
189 | |
102 string16 PhoneField::GetAreaRegex() const { | 190 string16 PhoneField::GetAreaRegex() const { |
103 // This one is the same for Home and Fax numbers. | 191 // This one is the same for Home and Fax numbers. |
104 return l10n_util::GetStringUTF16(IDS_AUTOFILL_AREA_CODE_RE); | 192 string16 area_code = l10n_util::GetStringUTF16(IDS_AUTOFILL_AREA_CODE_RE); |
193 area_code.append(ASCIIToUTF16("|")); // Regexp separator. | |
194 area_code.append(GetAreaNoTextRegex()); | |
195 return area_code; | |
196 } | |
197 | |
198 string16 PhoneField::GetAreaNoTextRegex() const { | |
199 // This one is the same for Home and Fax numbers. | |
200 return l10n_util::GetStringUTF16(IDS_AUTOFILL_AREA_CODE_NOTEXT_RE); | |
105 } | 201 } |
106 | 202 |
107 string16 PhoneField::GetPhoneRegex() const { | 203 string16 PhoneField::GetPhoneRegex() const { |
108 if (phone_type_ == HOME_PHONE) | 204 if (phone_type_ == HOME_PHONE) |
109 return l10n_util::GetStringUTF16(IDS_AUTOFILL_PHONE_RE); | 205 return l10n_util::GetStringUTF16(IDS_AUTOFILL_PHONE_RE); |
110 else if (phone_type_ == FAX_PHONE) | 206 else if (phone_type_ == FAX_PHONE) |
111 return l10n_util::GetStringUTF16(IDS_AUTOFILL_FAX_RE); | 207 return l10n_util::GetStringUTF16(IDS_AUTOFILL_FAX_RE); |
112 else | 208 else |
113 NOTREACHED(); | 209 NOTREACHED(); |
114 return string16(); | 210 return string16(); |
115 } | 211 } |
116 | 212 |
213 string16 PhoneField::GetPrefixSeparatorRegex() const { | |
214 // This one is the same for Home and Fax numbers. | |
215 return l10n_util::GetStringUTF16(IDS_AUTOFILL_PHONE_PREFIX_SEPARATOR_RE); | |
216 } | |
217 | |
117 string16 PhoneField::GetPrefixRegex() const { | 218 string16 PhoneField::GetPrefixRegex() const { |
118 // This one is the same for Home and Fax numbers. | 219 // This one is the same for Home and Fax numbers. |
119 return l10n_util::GetStringUTF16(IDS_AUTOFILL_PHONE_PREFIX_RE); | 220 return l10n_util::GetStringUTF16(IDS_AUTOFILL_PHONE_PREFIX_RE); |
120 } | 221 } |
121 | 222 |
223 string16 PhoneField::GetSuffixSeparatorRegex() const { | |
224 // This one is the same for Home and Fax numbers. | |
225 return l10n_util::GetStringUTF16(IDS_AUTOFILL_PHONE_SUFFIX_SEPARATOR_RE); | |
226 } | |
227 | |
122 string16 PhoneField::GetSuffixRegex() const { | 228 string16 PhoneField::GetSuffixRegex() const { |
123 // This one is the same for Home and Fax numbers. | 229 // This one is the same for Home and Fax numbers. |
124 return l10n_util::GetStringUTF16(IDS_AUTOFILL_PHONE_SUFFIX_RE); | 230 return l10n_util::GetStringUTF16(IDS_AUTOFILL_PHONE_SUFFIX_RE); |
125 } | 231 } |
126 | 232 |
127 string16 PhoneField::GetExtensionRegex() const { | 233 string16 PhoneField::GetExtensionRegex() const { |
128 // This one is the same for Home and Fax numbers. | 234 // This one is the same for Home and Fax numbers. |
129 return l10n_util::GetStringUTF16(IDS_AUTOFILL_PHONE_EXTENSION_RE); | 235 return l10n_util::GetStringUTF16(IDS_AUTOFILL_PHONE_EXTENSION_RE); |
130 } | 236 } |
131 | 237 |
238 string16 PhoneField::GetRegExp(RegexType regex_id) const { | |
239 switch (regex_id) { | |
240 case REGEX_COUNTRY: return GetCountryRegex(); | |
241 case REGEX_AREA: return GetAreaRegex(); | |
242 case REGEX_AREA_NOTEXT: return GetAreaNoTextRegex(); | |
243 case REGEX_PHONE: return GetPhoneRegex(); | |
244 case REGEX_PREFIX_SEPARATOR: return GetPrefixSeparatorRegex(); | |
245 case REGEX_PREFIX: return GetPrefixRegex(); | |
246 case REGEX_SUFFIX_SEPARATOR: return GetSuffixSeparatorRegex(); | |
247 case REGEX_SUFFIX: return GetSuffixRegex(); | |
248 case REGEX_EXTENSION: return GetExtensionRegex(); | |
249 default: | |
250 NOTREACHED(); | |
251 break; | |
252 } | |
253 return string16(); | |
254 } | |
255 | |
132 // static | 256 // static |
133 bool PhoneField::ParseInternal( | 257 bool PhoneField::ParseInternal( |
134 PhoneField *phone_field, | 258 PhoneField *phone_field, |
135 std::vector<AutoFillField*>::const_iterator* iter, | 259 std::vector<AutoFillField*>::const_iterator* iter, |
136 bool regular_phone) { | 260 bool regular_phone) { |
137 DCHECK(iter); | 261 DCHECK(iter); |
138 | 262 |
139 DCHECK(phone_field); | 263 DCHECK(phone_field); |
140 if (!phone_field) | 264 if (!phone_field) |
141 return false; | 265 return false; |
142 | 266 |
143 std::vector<AutoFillField*>::const_iterator q = *iter; | 267 std::vector<AutoFillField*>::const_iterator q = *iter; |
268 | |
144 // The form owns the following variables, so they should not be deleted. | 269 // The form owns the following variables, so they should not be deleted. |
145 AutoFillField* phone = NULL; | 270 AutoFillField* parsed_fields[FIELD_MAX]; |
146 AutoFillField* phone2 = NULL; | |
147 AutoFillField* phone3 = NULL; | |
148 bool area_code = false; // true if we've parsed an area code field. | |
149 | 271 |
150 // Some pages, such as BloomingdalesShipping.html, have a field labeled | 272 for (size_t i = 0; i < arraysize(phone_field_grammars_); ++i) { |
151 // "Area Code and Phone"; we want to parse this as a phone number field so | 273 memset(parsed_fields, 0, sizeof(parsed_fields)); |
152 // we look for "phone" before we look for "area code". | 274 q = *iter; |
153 if (ParseText(&q, phone_field->GetPhoneRegex(), &phone)) { | 275 // Attempt to parse next possible match. |
154 area_code = false; | 276 for (; i < arraysize(phone_field_grammars_) && |
155 // Check the case when the match is for non-home phone and area code, e.g. | 277 phone_field_grammars_[i].regex != REGEX_SEPARATOR; ++i) { |
156 // first field is a "Fax area code" and the subsequent is "Fax phone". | 278 if (!ParseText(&q, phone_field->GetRegExp(phone_field_grammars_[i].regex), |
157 if (!regular_phone) { | 279 &parsed_fields[phone_field_grammars_[i].phone_part])) |
158 // Attempt parsing of the same field as an area code and then phone: | 280 break; |
159 std::vector<AutoFillField*>::const_iterator temp_it = *iter; | 281 if (phone_field_grammars_[i].max_size && |
160 AutoFillField* tmp_phone1 = NULL; | 282 (!parsed_fields[phone_field_grammars_[i].phone_part]->max_length() || |
161 AutoFillField* tmp_phone2 = NULL; | 283 phone_field_grammars_[i].max_size < |
162 if (ParseText(&temp_it, phone_field->GetAreaRegex(), &tmp_phone1) && | 284 parsed_fields[phone_field_grammars_[i].phone_part]->max_length())) { |
163 ParseText(&temp_it, phone_field->GetPhoneRegex(), &tmp_phone2)) { | 285 break; |
164 phone = tmp_phone1; | |
165 phone2 = tmp_phone2; | |
166 q = temp_it; | |
167 area_code = true; | |
168 } | 286 } |
169 } | 287 } |
170 } else { | 288 if (i >= arraysize(phone_field_grammars_)) |
171 if (!ParseText(&q, phone_field->GetAreaRegex(), &phone)) | 289 return false; // Parsing failed. |
172 return false; | 290 if (phone_field_grammars_[i].regex == REGEX_SEPARATOR) |
173 area_code = true; | 291 break; // Parsing succeeded. |
174 // If this is not a home phone and there was no specification before | 292 do { |
175 // the phone number actually starts (e.g. field 1 "Area code:", field 2 | 293 ++i; |
176 // "Fax:"), we skip searching for preffix and suffix and bail out. | 294 } while (phone_field_grammars_[i].regex != REGEX_SEPARATOR); |
177 if (!ParseText(&q, phone_field->GetPhoneRegex(), &phone2) && !regular_phone) | |
178 return false; | |
179 } | 295 } |
296 if (!parsed_fields[FIELD_PHONE]) | |
297 return false; | |
Ilya Sherman
2011/02/16 23:22:08
Suppose the final pattern were "// Phone: <ac> - <
GeorgeY
2011/02/17 00:21:18
Nope. We will not get here until we have a complet
Ilya Sherman
2011/02/17 00:35:12
But there is no next pattern after the final patte
GeorgeY
2011/02/17 01:12:24
After the last pattern we bail out of the function
| |
180 | 298 |
181 // Sometimes phone number fields are separated by "-" (e.g. test page | 299 for (int i = 0; i < FIELD_MAX; ++i) |
182 // Crate and Barrel Check Out.html). Also, area codes are sometimes | 300 phone_field->parsed_phone_fields_[i] = parsed_fields[i]; |
183 // surrounded by parentheses, so a ")" may appear after the area code field. | 301 |
184 // | 302 // Look for optional fields. |
185 // We used to match "tel" here, which we've seen in field names (e.g. on | |
186 // Newegg2.html), but that's too general: some pages (e.g. | |
187 // uk/Furniture123-1.html) have several phone numbers in succession and we | |
188 // don't want those to be parsed as components of a single phone number. | |
189 if (phone2 == NULL) | |
190 ParseText(&q, phone_field->GetPrefixRegex(), &phone2); | |
191 | 303 |
192 // Look for a third text box. | 304 // Look for a third text box. |
193 if (phone2) | 305 if (!phone_field->parsed_phone_fields_[FIELD_SUFFIX]) { |
194 ParseText(&q, phone_field->GetSuffixRegex(), &phone3); | 306 if (!ParseText(&q, phone_field->GetSuffixRegex(), |
195 | 307 &phone_field->parsed_phone_fields_[FIELD_SUFFIX])) { |
196 // Now we have one, two, or three phone number text fields. Package them | 308 ParseText(&q, phone_field->GetSuffixSeparatorRegex(), |
197 // up into a PhoneField object. | 309 &phone_field->parsed_phone_fields_[FIELD_SUFFIX]); |
198 | |
199 if (phone2 == NULL) { // only one field | |
200 if (area_code) { | |
201 // It's an area code - it doesn't make sense. | |
202 return false; | |
203 } | |
204 phone_field->phone_ = phone; | |
205 } else { | |
206 phone_field->area_code_ = phone; | |
207 if (phone3 == NULL) { // two fields | |
208 phone_field->phone_ = phone2; | |
209 } else { // three boxes: area code, prefix and suffix | |
210 phone_field->prefix_ = phone2; | |
211 phone_field->phone_ = phone3; | |
212 } | 310 } |
213 } | 311 } |
214 | 312 |
215 // Now look for an extension. | 313 // Now look for an extension. |
216 ParseText(&q, phone_field->GetExtensionRegex(), &phone_field->extension_); | 314 ParseText(&q, phone_field->GetExtensionRegex(), |
315 &phone_field->parsed_phone_fields_[FIELD_EXTENSION]); | |
217 | 316 |
218 *iter = q; | 317 *iter = q; |
219 return true; | 318 return true; |
220 } | 319 } |
221 | 320 |
222 void PhoneField::SetPhoneType(PHONE_TYPE phone_type) { | 321 void PhoneField::SetPhoneType(PhoneType phone_type) { |
223 // Field types are different as well, so we create a temporary phone number, | 322 // Field types are different as well, so we create a temporary phone number, |
224 // to get relevant field types. | 323 // to get relevant field types. |
225 if (phone_type == HOME_PHONE) | 324 if (phone_type == HOME_PHONE) |
226 number_.reset(new HomePhoneNumber); | 325 number_.reset(new HomePhoneNumber); |
227 else | 326 else |
228 number_.reset(new FaxNumber); | 327 number_.reset(new FaxNumber); |
229 phone_type_ = phone_type; | 328 phone_type_ = phone_type; |
230 } | 329 } |
231 | 330 |
OLD | NEW |