Day 2 Afternoon Exercises

Luhn Algorithm

(back to exercise)

  1. // Copyright 2022 Google LLC
  2. //
  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
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  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.
  14. // ANCHOR: luhn
  15. pub fn luhn(cc_number: &str) -> bool {
  16. // ANCHOR_END: luhn
  17. let mut digits_seen = 0;
  18. let mut sum = 0;
  19. for (i, ch) in cc_number.chars().rev().filter(|&ch| ch != ' ').enumerate() {
  20. match ch.to_digit(10) {
  21. Some(d) => {
  22. sum += if i % 2 == 1 {
  23. let dd = d * 2;
  24. dd / 10 + dd % 10
  25. } else {
  26. d
  27. };
  28. digits_seen += 1;
  29. }
  30. None => return false,
  31. }
  32. }
  33. if digits_seen < 2 {
  34. return false;
  35. }
  36. sum % 10 == 0
  37. }
  38. fn main() {
  39. let cc_number = "1234 5678 1234 5670";
  40. println!(
  41. "Is {} a valid credit card number? {}",
  42. cc_number,
  43. if luhn(cc_number) { "yes" } else { "no" }
  44. );
  45. }
  46. // ANCHOR: unit-tests
  47. #[test]
  48. fn test_non_digit_cc_number() {
  49. assert!(!luhn("foo"));
  50. }
  51. #[test]
  52. fn test_empty_cc_number() {
  53. assert!(!luhn(""));
  54. assert!(!luhn(" "));
  55. assert!(!luhn(" "));
  56. assert!(!luhn(" "));
  57. }
  58. #[test]
  59. fn test_single_digit_cc_number() {
  60. assert!(!luhn("0"));
  61. }
  62. #[test]
  63. fn test_two_digit_cc_number() {
  64. assert!(luhn(" 0 0 "));
  65. }
  66. #[test]
  67. fn test_valid_cc_number() {
  68. assert!(luhn("4263 9826 4026 9299"));
  69. assert!(luhn("4539 3195 0343 6467"));
  70. assert!(luhn("7992 7398 713"));
  71. }
  72. #[test]
  73. fn test_invalid_cc_number() {
  74. assert!(!luhn("4223 9826 4026 9299"));
  75. assert!(!luhn("4539 3195 0343 6476"));
  76. assert!(!luhn("8273 1232 7352 0569"));
  77. }
  78. // ANCHOR_END: unit-tests

Strings and Iterators

(back to exercise)

  1. // Copyright 2022 Google LLC
  2. //
  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
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  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.
  14. // ANCHOR: prefix_matches
  15. pub fn prefix_matches(prefix: &str, request_path: &str) -> bool {
  16. // ANCHOR_END: prefix_matches
  17. let prefixes = prefix.split('/');
  18. let request_paths = request_path
  19. .split('/')
  20. .map(|p| Some(p))
  21. .chain(std::iter::once(None));
  22. for (prefix, request_path) in prefixes.zip(request_paths) {
  23. match request_path {
  24. Some(request_path) => {
  25. if (prefix != "*") && (prefix != request_path) {
  26. return false;
  27. }
  28. }
  29. None => return false,
  30. }
  31. }
  32. true
  33. }
  34. // ANCHOR: unit-tests
  35. #[test]
  36. fn test_matches_without_wildcard() {
  37. assert!(prefix_matches("/v1/publishers", "/v1/publishers"));
  38. assert!(prefix_matches("/v1/publishers", "/v1/publishers/abc-123"));
  39. assert!(prefix_matches("/v1/publishers", "/v1/publishers/abc/books"));
  40. assert!(!prefix_matches("/v1/publishers", "/v1"));
  41. assert!(!prefix_matches("/v1/publishers", "/v1/publishersBooks"));
  42. assert!(!prefix_matches("/v1/publishers", "/v1/parent/publishers"));
  43. }
  44. #[test]
  45. fn test_matches_with_wildcard() {
  46. assert!(prefix_matches(
  47. "/v1/publishers/*/books",
  48. "/v1/publishers/foo/books"
  49. ));
  50. assert!(prefix_matches(
  51. "/v1/publishers/*/books",
  52. "/v1/publishers/bar/books"
  53. ));
  54. assert!(prefix_matches(
  55. "/v1/publishers/*/books",
  56. "/v1/publishers/foo/books/book1"
  57. ));
  58. assert!(!prefix_matches("/v1/publishers/*/books", "/v1/publishers"));
  59. assert!(!prefix_matches(
  60. "/v1/publishers/*/books",
  61. "/v1/publishers/foo/booksByAuthor"
  62. ));
  63. }
  64. // ANCHOR_END: unit-tests
  65. fn main() {}