1 // Copyright (C) 2013 Google Inc.
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
7 // http://www.apache.org/licenses/LICENSE-2.0
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.
25 #include "address_field_util.h"
26 #include "format_element.h"
29 #include "region_data_constants.h"
30 #include "util/json.h"
31 #include "util/re2ptr.h"
32 #include "util/string_split.h"
35 namespace addressinput {
39 typedef std::map<std::string, int> NameMessageIdMap;
41 // Used as a separator in a list of items. For example, the list of supported
42 // languages can be "de~fr~it".
43 const char kSeparator = '~';
45 NameMessageIdMap InitAdminAreaMessageIds() {
46 NameMessageIdMap message_ids;
47 message_ids.insert(std::make_pair(
48 "area", IDS_LIBADDRESSINPUT_AREA));
49 message_ids.insert(std::make_pair(
50 "county", IDS_LIBADDRESSINPUT_COUNTY));
51 message_ids.insert(std::make_pair(
52 "department", IDS_LIBADDRESSINPUT_DEPARTMENT));
53 message_ids.insert(std::make_pair(
54 "district", IDS_LIBADDRESSINPUT_DISTRICT));
55 message_ids.insert(std::make_pair(
56 "do_si", IDS_LIBADDRESSINPUT_DO_SI));
57 message_ids.insert(std::make_pair(
58 "emirate", IDS_LIBADDRESSINPUT_EMIRATE));
59 message_ids.insert(std::make_pair(
60 "island", IDS_LIBADDRESSINPUT_ISLAND));
61 message_ids.insert(std::make_pair(
62 "oblast", IDS_LIBADDRESSINPUT_OBLAST));
63 message_ids.insert(std::make_pair(
64 "parish", IDS_LIBADDRESSINPUT_PARISH));
65 message_ids.insert(std::make_pair(
66 "prefecture", IDS_LIBADDRESSINPUT_PREFECTURE));
67 message_ids.insert(std::make_pair(
68 "province", IDS_LIBADDRESSINPUT_PROVINCE));
69 message_ids.insert(std::make_pair(
70 "state", IDS_LIBADDRESSINPUT_STATE));
74 const NameMessageIdMap& GetAdminAreaMessageIds() {
75 static const NameMessageIdMap kAdminAreaMessageIds(InitAdminAreaMessageIds());
76 return kAdminAreaMessageIds;
79 NameMessageIdMap InitPostalCodeMessageIds() {
80 NameMessageIdMap message_ids;
81 message_ids.insert(std::make_pair(
82 "postal", IDS_LIBADDRESSINPUT_POSTAL_CODE_LABEL));
83 message_ids.insert(std::make_pair(
84 "zip", IDS_LIBADDRESSINPUT_ZIP_CODE_LABEL));
88 const NameMessageIdMap& GetPostalCodeMessageIds() {
89 static const NameMessageIdMap kPostalCodeMessageIds(
90 InitPostalCodeMessageIds());
91 return kPostalCodeMessageIds;
94 NameMessageIdMap InitLocalityMessageIds() {
95 NameMessageIdMap message_ids;
96 message_ids.insert(std::make_pair(
97 "city", IDS_LIBADDRESSINPUT_LOCALITY_LABEL));
98 message_ids.insert(std::make_pair(
99 "post_town", IDS_LIBADDRESSINPUT_POST_TOWN));
100 message_ids.insert(std::make_pair(
101 "district", IDS_LIBADDRESSINPUT_DISTRICT));
105 const NameMessageIdMap& GetLocalityMessageIds() {
106 static const NameMessageIdMap kLocalityMessageIds(
107 InitLocalityMessageIds());
108 return kLocalityMessageIds;
111 NameMessageIdMap InitSublocalityMessageIds() {
112 NameMessageIdMap message_ids;
113 message_ids.insert(std::make_pair(
114 "suburb", IDS_LIBADDRESSINPUT_SUBURB));
115 message_ids.insert(std::make_pair(
116 "district", IDS_LIBADDRESSINPUT_DISTRICT));
117 message_ids.insert(std::make_pair(
118 "neighborhood", IDS_LIBADDRESSINPUT_NEIGHBORHOOD));
119 message_ids.insert(std::make_pair(
120 "village_township", IDS_LIBADDRESSINPUT_VILLAGE_TOWNSHIP));
124 const NameMessageIdMap& GetSublocalityMessageIds() {
125 static const NameMessageIdMap kSublocalityMessageIds(
126 InitSublocalityMessageIds());
127 return kSublocalityMessageIds;
130 int GetMessageIdFromName(const std::string& name,
131 const NameMessageIdMap& message_ids) {
132 NameMessageIdMap::const_iterator it = message_ids.find(name);
133 return it != message_ids.end() ? it->second : INVALID_MESSAGE_ID;
136 // Determines whether a given string is a reg-exp or a string. We consider a
137 // string to be anything that doesn't contain characters with special meanings
138 // in regular expressions - (, [, \, {, ?. These special characters are all the
139 // ones that appear in the postal code regular expressions.
140 bool ContainsRegExSpecialCharacters(const std::string& input) {
141 return input.find_first_of("([\\{?") != std::string::npos;
153 postal_code_matcher_(NULL),
155 admin_area_name_message_id_(INVALID_MESSAGE_ID),
156 postal_code_name_message_id_(INVALID_MESSAGE_ID),
157 locality_name_message_id_(INVALID_MESSAGE_ID),
158 sublocality_name_message_id_(INVALID_MESSAGE_ID),
161 postal_code_example_(),
162 post_service_url_() {}
167 const Rule& Rule::GetDefault() {
168 // Allocated once and leaked on shutdown.
169 static Rule* default_rule = NULL;
170 if (default_rule == NULL) {
171 default_rule = new Rule;
172 default_rule->ParseSerializedRule(
173 RegionDataConstants::GetDefaultRegionData());
175 return *default_rule;
178 void Rule::CopyFrom(const Rule& rule) {
179 assert(this != &rule);
181 format_ = rule.format_;
182 latin_format_ = rule.latin_format_;
183 required_ = rule.required_;
184 sub_keys_ = rule.sub_keys_;
185 languages_ = rule.languages_;
186 postal_code_matcher_.reset(
187 rule.postal_code_matcher_ == NULL
189 : new RE2ptr(new RE2(rule.postal_code_matcher_->ptr->pattern(),
190 rule.postal_code_matcher_->ptr->options())));
191 sole_postal_code_ = rule.sole_postal_code_;
192 admin_area_name_message_id_ = rule.admin_area_name_message_id_;
193 postal_code_name_message_id_ = rule.postal_code_name_message_id_;
194 locality_name_message_id_ = rule.locality_name_message_id_;
195 sublocality_name_message_id_ = rule.sublocality_name_message_id_;
197 latin_name_ = rule.latin_name_;
198 postal_code_example_ = rule.postal_code_example_;
199 post_service_url_ = rule.post_service_url_;
202 bool Rule::ParseSerializedRule(const std::string& serialized_rule) {
204 if (!json.ParseObject(serialized_rule)) {
211 void Rule::ParseJsonRule(const Json& json) {
213 if (json.GetStringValueForKey("id", &value)) {
217 if (json.GetStringValueForKey("fmt", &value)) {
218 ParseFormatRule(value, &format_);
221 if (json.GetStringValueForKey("lfmt", &value)) {
222 ParseFormatRule(value, &latin_format_);
225 if (json.GetStringValueForKey("require", &value)) {
226 ParseAddressFieldsRequired(value, &required_);
229 if (json.GetStringValueForKey("sub_keys", &value)) {
230 SplitString(value, kSeparator, &sub_keys_);
233 if (json.GetStringValueForKey("languages", &value)) {
234 SplitString(value, kSeparator, &languages_);
237 sole_postal_code_.clear();
238 if (json.GetStringValueForKey("zip", &value)) {
239 // The "zip" field in the JSON data is used in two different ways to
240 // validate the postal code. At the country level, the "zip" field indicates
241 // a Java compatible regular expression corresponding to all postal codes in
242 // the country. At other levels, the regular expression indicates the postal
243 // code prefix expected for addresses in that region.
245 // In order to make the RE2 object created from the "zip" field useable for
246 // both these purposes, the pattern string is here prefixed with "^" to
247 // anchor it at the beginning of the string so that it can be used with
248 // RE2::PartialMatch() to perform prefix matching or else with
249 // RE2::FullMatch() to perform matching against the entire string.
250 RE2::Options options;
251 options.set_never_capture(true);
252 RE2* matcher = new RE2("^(" + value + ")", options);
254 postal_code_matcher_.reset(new RE2ptr(matcher));
256 postal_code_matcher_.reset(NULL);
259 // If the "zip" field is not a regular expression, then it is the sole
260 // postal code for this rule.
261 if (!ContainsRegExSpecialCharacters(value)) {
262 sole_postal_code_.swap(value);
266 if (json.GetStringValueForKey("state_name_type", &value)) {
267 admin_area_name_message_id_ =
268 GetMessageIdFromName(value, GetAdminAreaMessageIds());
271 if (json.GetStringValueForKey("zip_name_type", &value)) {
272 postal_code_name_message_id_ =
273 GetMessageIdFromName(value, GetPostalCodeMessageIds());
276 if (json.GetStringValueForKey("locality_name_type", &value)) {
277 locality_name_message_id_ =
278 GetMessageIdFromName(value, GetLocalityMessageIds());
281 if (json.GetStringValueForKey("sublocality_name_type", &value)) {
282 sublocality_name_message_id_ =
283 GetMessageIdFromName(value, GetSublocalityMessageIds());
286 if (json.GetStringValueForKey("name", &value)) {
290 if (json.GetStringValueForKey("lname", &value)) {
291 latin_name_.swap(value);
294 if (json.GetStringValueForKey("zipex", &value)) {
295 postal_code_example_.swap(value);
298 if (json.GetStringValueForKey("posturl", &value)) {
299 post_service_url_.swap(value);
303 } // namespace addressinput