Luhn
1. Readme
Luhn
给定一个数,判定它是否有效 Luhn 公式.
Luhn 算法,也称为“模 10”算法
这个Luhn 算法是一个简单的校验和公式,用于验证各种身份号码,如信用卡号码和加拿大社会保险号码.
任务是检查给定字符串是否有效.
验证一个数
长度为 1 或更小的字符串无效。在输入中允许使用空格,但在检查前,应清除空格。所有其他非数字字符都是不允许的.
例子 1:有效信用卡号码
4539 1488 0343 6467
LuHN 算法的第一步是,从右边开始每第二个数字加倍。我们要加倍的位
4_3_ 1_8_ 0_4_ 6_6_
如果加倍的数字值导致大于 9 的数字,则将此值减去 9。我们加倍的结果:
8569 2478 0383 3437
1_8_ => 2_7_
,8*2 - 9 = 7
然后把所有数字加起来:
8+5+6+9+2+4+7+8+0+3+8+3+3+4+3+7 = 80
如果总和可被 10 整除,则数字是有效的.这个号码是有效的!
例子 2:信用卡号码无效
8273 1232 7352 0569
把每第二个数字加倍,从右边开始
7253 2262 5312 0539
合计数字
7+2+5+3+2+2+6+2+5+3+1+2+0+5+3+9 = 57
57 不能被 10 整除,所以这个数字是无效的.
资源
维基百科上的 LuHn 算法http://en.wikipedia.org/wiki/Luhn_algorithm
2. 开始你的表演
/// Check a Luhn checksum. pub fn is_valid(code: &str) -> bool { unimplemented!("Is the Luhn checksum for {} valid?", code); }
3. 测试代码查看
# #![allow(unused_variables)] #fn main() { #[test] fn single_digit_string_is_invalid() { assert!(!is_valid("1")); } #[test] //#[ignore] fn single_zero_string_is_invalid() { assert!(!is_valid("0")); } #[test] //#[ignore] fn simple_valid_sin() { assert!(is_valid(" 5 9 ")); } #[test] //#[ignore] fn valid_canadian_sin_is_valid() { assert!(is_valid("046 454 286")); } #[test] //#[ignore] fn invalid_canadian_sin_is_invalid() { assert!(!is_valid("046 454 287")); } #[test] //#[ignore] fn invalid_credit_card_is_invalid() { assert!(!is_valid("8273 1232 7352 0569")); } #[test] //#[ignore] fn strings_that_contain_non_digits_are_invalid() { assert!(!is_valid("046a 454 286")); } #[test] //#[ignore] fn punctuation_is_invalid() { assert!(!is_valid("055-444-285")); } #[test] //#[ignore] fn symbols_are_invalid() { assert!(!is_valid("055£ 444$ 285")); } #[test] //#[ignore] fn single_digit_with_space_is_invalid() { assert!(!is_valid(" 0")); } #[test] //#[ignore] fn lots_of_zeros_are_valid() { assert!(is_valid(" 00000")); } #[test] //#[ignore] fn another_valid_sin() { assert!(is_valid("055 444 285")); } #[test] //#[ignore] fn nine_doubled_is_nine() { assert!(is_valid("091")); } #}
4. 答案
# #![allow(unused_variables)] #fn main() { pub fn is_valid(candidate: &str) -> bool { if candidate.chars().filter(|c| c.is_digit(10)).take(2).count() <= 1 || candidate.chars().any(|c| !c.is_digit(10) && c != ' ') { return false; } candidate .chars() .filter_map(|c| c.to_digit(10)) .rev() .enumerate() .map(|(index, digit)| if index % 2 == 0 { digit } else { digit * 2 }) .map(|digit| if digit > 9 { digit - 9 } else { digit }) .sum::<u32>() % 10 == 0 } #}