Skip to content

Commit 7bfa0d8

Browse files
committed
Added is_valid_email_address.rs
add is_valid_email_address.rs
1 parent 2d2ffc4 commit 7bfa0d8

File tree

3 files changed

+115
-0
lines changed

3 files changed

+115
-0
lines changed

DIRECTORY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,7 @@
314314
* [Burrows Wheeler Transform](https://github.com/TheAlgorithms/Rust/blob/master/src/string/burrows_wheeler_transform.rs)
315315
* [Duval Algorithm](https://github.com/TheAlgorithms/Rust/blob/master/src/string/duval_algorithm.rs)
316316
* [Hamming Distance](https://github.com/TheAlgorithms/Rust/blob/master/src/string/hamming_distance.rs)
317+
* [Is Valid Email Address](https://github.com/TheAlgorithms/Rust/blob/master/src/string/is_valid_email_address.rs)
317318
* [Isomorphism](https://github.com/TheAlgorithms/Rust/blob/master/src/string/isomorphism.rs)
318319
* [Jaro Winkler Distance](https://github.com/TheAlgorithms/Rust/blob/master/src/string/jaro_winkler_distance.rs)
319320
* [Knuth Morris Pratt](https://github.com/TheAlgorithms/Rust/blob/master/src/string/knuth_morris_pratt.rs)

src/string/is_valid_email_address.rs

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
const MAX_LOCAL_PART_LENGTH: u32 = 64;
2+
const MAX_DOMAIN_LENGTH: u32 = 255;
3+
const CHARACTERS: &str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890";
4+
const SYMBOLS: &str = "!#$%&'*+-/=?^_`{|}~";
5+
6+
/// Returns true if email address is valid, otherwise returns false
7+
///
8+
/// A valid email address is made up of two parts, the local-part, and
9+
/// the domain.
10+
///
11+
/// The local-part may contain the following:
12+
/// - uppercase & lowercase latin letters
13+
/// - digits 0-9
14+
/// - characters !#$%&'*+-/=?^_`{|}~
15+
/// - non consecutive dots ('.') not located at start or end of local-part
16+
///
17+
/// The domain may contain the following:
18+
/// - uppercase & lowercase latin letters
19+
/// - digits 0-9
20+
/// - dash ('-') as long as not at start or end of domain
21+
///
22+
/// The local-part and domain must be separated by an '@'
23+
/// The local-part must not contain more than 64 characters
24+
/// The domain must not contain more than 255 characters
25+
pub fn is_valid_email_address(email_address: &str) -> bool {
26+
let parts: Vec<String> = email_address
27+
.split('@')
28+
.map(|x| x.to_string())
29+
.collect::<Vec<String>>();
30+
31+
// (1) ensure there is only one '@' symbol in the address
32+
if parts.len() != 2 {
33+
return false;
34+
}
35+
36+
let (local_part, domain): (String, String) = (parts[0].clone(), parts[1].clone());
37+
38+
// (2) check that the length of the two parts are within the valid range
39+
if local_part.len() > MAX_LOCAL_PART_LENGTH as usize
40+
|| domain.len() > MAX_DOMAIN_LENGTH as usize
41+
{
42+
return false;
43+
}
44+
45+
// (3) validate the dots in the local part
46+
if local_part.starts_with('.') || local_part.ends_with('.') || local_part.contains("..") {
47+
return false;
48+
}
49+
50+
// (4) check that the characters in the local part are valid
51+
for item in local_part.chars() {
52+
if !CHARACTERS.contains(item) && !SYMBOLS.contains(item) && item != '.' {
53+
return false;
54+
}
55+
}
56+
57+
// (5) check that the domain contains valid characters
58+
for item in domain.chars() {
59+
if !CHARACTERS.contains(item) && item != '-' && item != '.' {
60+
return false;
61+
}
62+
}
63+
64+
// (6) validate the dots in the domain
65+
if domain.starts_with('.') || domain.ends_with('.') || domain.contains("..") {
66+
return false;
67+
}
68+
69+
// (7) validate the dashes in the domain
70+
if domain.starts_with('-') || domain.ends_with('-') {
71+
return false;
72+
}
73+
74+
true
75+
}
76+
77+
#[cfg(test)]
78+
mod tests {
79+
use crate::string::is_valid_email_address::is_valid_email_address;
80+
81+
macro_rules! test_is_valid_email_address {
82+
($($name:ident: $inputs:expr,)*) => {
83+
$(
84+
#[test]
85+
fn $name() {
86+
let (s, expected) = $inputs;
87+
assert_eq!(is_valid_email_address(s), expected);
88+
}
89+
)*
90+
}
91+
}
92+
93+
test_is_valid_email_address! {
94+
normal_email: ("[email protected]", true),
95+
email_with_dots: ("[email protected]", true),
96+
dots_with_symbols: ("[email protected]", true),
97+
dash_test: ("[email protected]", true),
98+
short_local_part: ("[email protected]", true),
99+
multiple_dash: ("[email protected]", true),
100+
extreme_valid: ("longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglon@example.com",true),
101+
extreme_invalid: ("longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglongl@example.com",false),
102+
invalid_at: ("where.is.at", false),
103+
multiple_ats: ("too@[email protected]", false),
104+
consecutive_dots: ("[email protected]", false),
105+
invalid_underscore: ("wrong@no_underscore_here", false),
106+
dash_start: ("[email protected]", false),
107+
dash_end: ("also-dont-put@here-", false),
108+
dot_start: (".not_at_start@dont", false),
109+
dot_end: ("or-at-end@here.", false),
110+
dot_start_end: ("[email protected].", false),
111+
}
112+
}

src/string/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ mod boyer_moore_search;
55
mod burrows_wheeler_transform;
66
mod duval_algorithm;
77
mod hamming_distance;
8+
mod is_valid_email_address;
89
mod isomorphism;
910
mod jaro_winkler_distance;
1011
mod knuth_morris_pratt;
@@ -31,6 +32,7 @@ pub use self::burrows_wheeler_transform::{
3132
};
3233
pub use self::duval_algorithm::duval_algorithm;
3334
pub use self::hamming_distance::hamming_distance;
35+
pub use self::is_valid_email_address::is_valid_email_address;
3436
pub use self::isomorphism::is_isomorphic;
3537
pub use self::jaro_winkler_distance::jaro_winkler_distance;
3638
pub use self::knuth_morris_pratt::knuth_morris_pratt;

0 commit comments

Comments
 (0)