@@ -184,6 +184,55 @@ def format_region_code(self, region_code: str) -> str:
184184 raise ValueError ("Region code must be two characters" )
185185 return region_code
186186
187+ def _format_location_string (self , value : str , label : str ) -> str :
188+ """Returns the normalized and formatted location string.
189+
190+ Args:
191+ value: the string to format.
192+ label: the label used for error messages.
193+ Raises:
194+ ValueError: If the provided value is invalid.
195+ """
196+ if value is None :
197+ raise ValueError (f"{ label } is None" )
198+ value = value .strip ().lower ()
199+ # Removes all punctuation and special characters, leaving only
200+ # alphanumeric characters and whitespace.
201+ value = re .sub (r"[^\w\s]|_" , "" , value )
202+ if not value :
203+ raise ValueError (f"{ label } is blank or empty" )
204+ return value
205+
206+ def format_address_line (self , address_line : str ) -> str :
207+ """Returns the normalized and formatted address line as a string.
208+
209+ Args:
210+ address_line: the address line.
211+ Raises:
212+ ValueError: If the provided address line is invalid.
213+ """
214+ return self ._format_location_string (address_line , "Address line" )
215+
216+ def format_city (self , city : str ) -> str :
217+ """Returns the normalized and formatted city as a string.
218+
219+ Args:
220+ city: the city.
221+ Raises:
222+ ValueError: If the provided city is invalid.
223+ """
224+ return self ._format_location_string (city , "City" )
225+
226+ def format_administrative_area (self , administrative_area : str ) -> str :
227+ """Returns the normalized and formatted administrative area as a string.
228+
229+ Args:
230+ administrative_area: the administrative area.
231+ Raises:
232+ ValueError: If the provided administrative area is invalid.
233+ """
234+ return self ._format_location_string (administrative_area , "Administrative area" )
235+
187236 def hash_string (self , s : str ) -> bytes :
188237 """Returns bytes containing the hash of the string.
189238
@@ -195,8 +244,7 @@ def hash_string(self, s: str) -> bytes:
195244 """
196245 if s is None :
197246 raise ValueError ("String is None" )
198- s = "" .join (s .split ())
199- if len (s ) == 0 :
247+ if len (s .strip ()) == 0 :
200248 raise ValueError ("String is blank or empty" )
201249 return hashlib .sha256 (s .encode ()).digest ()
202250
@@ -350,6 +398,55 @@ def process_postal_code(self, postal_code: str) -> str:
350398 """
351399 return self .format_postal_code (postal_code )
352400
401+ def process_address_line (
402+ self ,
403+ address_line : str ,
404+ encoding : Encoding ,
405+ encrypter : Optional [Encrypter ] = None ,
406+ ) -> str :
407+ """Formats, hashes, and encodes an address line.
408+
409+ Args:
410+ address_line: The address line to process.
411+ encoding: The encoding to use.
412+ encrypter: An optional Encrypter to use for encryption.
413+
414+ Returns:
415+ The processed address line.
416+ """
417+ formatted_address_line = self .format_address_line (address_line )
418+ if encrypter :
419+ return self ._hash_encode_and_encrypt (
420+ formatted_address_line , encoding , encrypter
421+ )
422+ return self ._hash_and_encode (formatted_address_line , encoding )
423+
424+ def process_city (self , city : str ) -> str :
425+ """Processes a city.
426+
427+ This is a convenience method that simply calls format_city.
428+
429+ Args:
430+ city: The city to process.
431+
432+ Returns:
433+ The processed city.
434+ """
435+ return self .format_city (city )
436+
437+ def process_administrative_area (self , administrative_area : str ) -> str :
438+ """Processes an administrative area.
439+
440+ This is a convenience method that simply calls format_administrative_area.
441+
442+ Args:
443+ administrative_area: The administrative area to process.
444+
445+ Returns:
446+ The processed administrative area.
447+ """
448+ return self .format_administrative_area (administrative_area )
449+
353450 def _hash_and_encode (
354451 self , normalized_string : str , encoding : Encoding
355452 ) -> str :
0 commit comments