diff --git a/dart/phone-number/HELP.md b/dart/phone-number/HELP.md new file mode 100644 index 0000000..ffb5070 --- /dev/null +++ b/dart/phone-number/HELP.md @@ -0,0 +1,38 @@ +# Help + +## Running the tests + +To run the tests: + +```sh +$ dart test +``` + +## Submitting your solution + +You can submit your solution using the `exercism submit lib/phone_number.dart` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Dart track's documentation](https://exercism.org/docs/tracks/dart) +- The [Dart track's programming category on the forum](https://forum.exercism.org/c/programming/dart) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +To get help if you're having trouble, you can use one of the following resources: + +- [Dart API Documentation](https://api.dart.dev/) +- [Dart Gitter Chat](https://gitter.im/dart-lang/home) +- [Community Information](https://www.dart.dev/community) +- [/r/dartlang](https://www.reddit.com/r/dartlang) is the Dart subreddit. +- [StackOverflow](https://stackoverflow.com/questions/tagged/dart) can be used to search for your problem and see if it has been answered already. You can also ask and answer questions. \ No newline at end of file diff --git a/dart/phone-number/README.md b/dart/phone-number/README.md new file mode 100644 index 0000000..5496a79 --- /dev/null +++ b/dart/phone-number/README.md @@ -0,0 +1,75 @@ +# Phone Number + +Welcome to Phone Number on Exercism's Dart Track. +If you need help running the tests or submitting your code, check out `HELP.md`. + +## Instructions + +Clean up user-entered phone numbers so that they can be sent SMS messages. + +The **North American Numbering Plan (NANP)** is a telephone numbering system used by many countries in North America like the United States, Canada or Bermuda. +All NANP-countries share the same international country code: `1`. + +NANP numbers are ten-digit numbers consisting of a three-digit Numbering Plan Area code, commonly known as *area code*, followed by a seven-digit local number. +The first three digits of the local number represent the *exchange code*, followed by the unique four-digit number which is the *subscriber number*. + +The format is usually represented as + +```text +(NXX)-NXX-XXXX +``` + +where `N` is any digit from 2 through 9 and `X` is any digit from 0 through 9. + +Your task is to clean up differently formatted telephone numbers by removing punctuation and the country code (1) if present. + +For example, the inputs + +- `+1 (613)-995-0253` +- `613-995-0253` +- `1 613 995 0253` +- `613.995.0253` + +should all produce the output + +`6139950253` + +**Note:** As this exercise only deals with telephone numbers used in NANP-countries, only 1 is considered a valid country code. + +A function with a *return type* can only return data of that *type* and `null`. +However the function caller is only expecting one data type. + +Example: +```dart +String hello(int a){ + if ( a == 0){ + return "a"; + } else { + return null; + } +} +``` +To make it more clear that this function can also return `null` or more data types, use `dynamic`. +```dart +dynamic hello(int a){ + if ( a == 0){ + return "a"; + } else { + return null; + } +} + +## Source + +### Created by + +- @devkabiir + +### Contributed to by + +- @kytrinyx +- @Stargator + +### Based on + +Exercise by the JumpstartLab team for students at The Turing School of Software and Design. - https://turing.edu \ No newline at end of file diff --git a/dart/phone-number/analysis_options.yaml b/dart/phone-number/analysis_options.yaml new file mode 100644 index 0000000..c06363d --- /dev/null +++ b/dart/phone-number/analysis_options.yaml @@ -0,0 +1,18 @@ +analyzer: + strong-mode: + implicit-casts: false + implicit-dynamic: false + errors: + unused_element: error + unused_import: error + unused_local_variable: error + dead_code: error + +linter: + rules: + # Error Rules + - avoid_relative_lib_imports + - avoid_types_as_parameter_names + - literal_only_boolean_expressions + - no_adjacent_strings_in_list + - valid_regexps diff --git a/dart/phone-number/lib/phone_number.dart b/dart/phone-number/lib/phone_number.dart new file mode 100644 index 0000000..31837ba --- /dev/null +++ b/dart/phone-number/lib/phone_number.dart @@ -0,0 +1,37 @@ +class PhoneNumber { + String clean(String number) { + String cleaned = number.replaceAll(RegExp('[ \-\.]'), ''); + + if (cleaned.contains(RegExp('[A-Za-z]'))) { + throw FormatException('letters not permitted'); + } + if (cleaned.contains(RegExp('[^0-9]'))) { + throw FormatException('punctuations not permitted'); + } + if (cleaned.length < 10) { + throw FormatException('must not be fewer than 10 digits'); + } + if (cleaned.length > 11) { + throw FormatException('must not be greater than 11 digits'); + } + if (cleaned.length == 11 && cleaned[0] != '1') { + throw FormatException('11 digits must start with 1'); + } + if (cleaned.length == 11) { + cleaned = cleaned.substring(1); + } + if(cleaned[0] == '0') { + throw FormatException('area code cannot start with zero'); + } + if(cleaned[0] == '1') { + throw FormatException('area code cannot start with one'); + } + if(cleaned[3] == '0') { + throw FormatException('exchange code cannot start with zero'); + } + if(cleaned[3] == '1') { + throw FormatException('exchange code cannot start with one'); + } + return cleaned; + } +} diff --git a/dart/phone-number/pubspec.lock b/dart/phone-number/pubspec.lock new file mode 100644 index 0000000..d276822 --- /dev/null +++ b/dart/phone-number/pubspec.lock @@ -0,0 +1,365 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + _fe_analyzer_shared: + dependency: transitive + description: + name: _fe_analyzer_shared + sha256: ae92f5d747aee634b87f89d9946000c2de774be1d6ac3e58268224348cd0101a + url: "https://pub.dev" + source: hosted + version: "61.0.0" + analyzer: + dependency: transitive + description: + name: analyzer + sha256: ea3d8652bda62982addfd92fdc2d0214e5f82e43325104990d4f4c4a2a313562 + url: "https://pub.dev" + source: hosted + version: "5.13.0" + args: + dependency: transitive + description: + name: args + sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596 + url: "https://pub.dev" + source: hosted + version: "2.4.2" + async: + dependency: transitive + description: + name: async + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + url: "https://pub.dev" + source: hosted + version: "2.11.0" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + collection: + dependency: transitive + description: + name: collection + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + url: "https://pub.dev" + source: hosted + version: "1.18.0" + convert: + dependency: transitive + description: + name: convert + sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" + url: "https://pub.dev" + source: hosted + version: "3.1.1" + coverage: + dependency: transitive + description: + name: coverage + sha256: "595a29b55ce82d53398e1bcc2cba525d7bd7c59faeb2d2540e9d42c390cfeeeb" + url: "https://pub.dev" + source: hosted + version: "1.6.4" + crypto: + dependency: transitive + description: + name: crypto + sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab + url: "https://pub.dev" + source: hosted + version: "3.0.3" + file: + dependency: transitive + description: + name: file + sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d" + url: "https://pub.dev" + source: hosted + version: "6.1.4" + frontend_server_client: + dependency: transitive + description: + name: frontend_server_client + sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612" + url: "https://pub.dev" + source: hosted + version: "3.2.0" + glob: + dependency: transitive + description: + name: glob + sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + http_multi_server: + dependency: transitive + description: + name: http_multi_server + sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b" + url: "https://pub.dev" + source: hosted + version: "3.2.1" + http_parser: + dependency: transitive + description: + name: http_parser + sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + url: "https://pub.dev" + source: hosted + version: "4.0.2" + io: + dependency: transitive + description: + name: io + sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e" + url: "https://pub.dev" + source: hosted + version: "1.0.4" + js: + dependency: transitive + description: + name: js + sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 + url: "https://pub.dev" + source: hosted + version: "0.6.7" + logging: + dependency: transitive + description: + name: logging + sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + matcher: + dependency: transitive + description: + name: matcher + sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" + url: "https://pub.dev" + source: hosted + version: "0.12.16" + meta: + dependency: transitive + description: + name: meta + sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04 + url: "https://pub.dev" + source: hosted + version: "1.11.0" + mime: + dependency: transitive + description: + name: mime + sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e + url: "https://pub.dev" + source: hosted + version: "1.0.4" + node_preamble: + dependency: transitive + description: + name: node_preamble + sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db" + url: "https://pub.dev" + source: hosted + version: "2.0.2" + package_config: + dependency: transitive + description: + name: package_config + sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + path: + dependency: transitive + description: + name: path + sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" + url: "https://pub.dev" + source: hosted + version: "1.8.3" + pool: + dependency: transitive + description: + name: pool + sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a" + url: "https://pub.dev" + source: hosted + version: "1.5.1" + pub_semver: + dependency: transitive + description: + name: pub_semver + sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + shelf: + dependency: transitive + description: + name: shelf + sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4 + url: "https://pub.dev" + source: hosted + version: "1.4.1" + shelf_packages_handler: + dependency: transitive + description: + name: shelf_packages_handler + sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e" + url: "https://pub.dev" + source: hosted + version: "3.0.2" + shelf_static: + dependency: transitive + description: + name: shelf_static + sha256: a41d3f53c4adf0f57480578c1d61d90342cd617de7fc8077b1304643c2d85c1e + url: "https://pub.dev" + source: hosted + version: "1.1.2" + shelf_web_socket: + dependency: transitive + description: + name: shelf_web_socket + sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1" + url: "https://pub.dev" + source: hosted + version: "1.0.4" + source_map_stack_trace: + dependency: transitive + description: + name: source_map_stack_trace + sha256: "84cf769ad83aa6bb61e0aa5a18e53aea683395f196a6f39c4c881fb90ed4f7ae" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + source_maps: + dependency: transitive + description: + name: source_maps + sha256: "708b3f6b97248e5781f493b765c3337db11c5d2c81c3094f10904bfa8004c703" + url: "https://pub.dev" + source: hosted + version: "0.10.12" + source_span: + dependency: transitive + description: + name: source_span + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" + url: "https://pub.dev" + source: hosted + version: "1.10.0" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" + url: "https://pub.dev" + source: hosted + version: "1.11.1" + stream_channel: + dependency: transitive + description: + name: stream_channel + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 + url: "https://pub.dev" + source: hosted + version: "2.1.2" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" + source: hosted + version: "1.2.1" + test: + dependency: "direct dev" + description: + name: test + sha256: "13b41f318e2a5751c3169137103b60c584297353d4b1761b66029bae6411fe46" + url: "https://pub.dev" + source: hosted + version: "1.24.3" + test_api: + dependency: transitive + description: + name: test_api + sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8" + url: "https://pub.dev" + source: hosted + version: "0.6.0" + test_core: + dependency: transitive + description: + name: test_core + sha256: "99806e9e6d95c7b059b7a0fc08f07fc53fabe54a829497f0d9676299f1e8637e" + url: "https://pub.dev" + source: hosted + version: "0.5.3" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c + url: "https://pub.dev" + source: hosted + version: "1.3.2" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: c538be99af830f478718b51630ec1b6bee5e74e52c8a802d328d9e71d35d2583 + url: "https://pub.dev" + source: hosted + version: "11.10.0" + watcher: + dependency: transitive + description: + name: watcher + sha256: "6a7f46926b01ce81bfc339da6a7f20afbe7733eff9846f6d6a5466aa4c6667c0" + url: "https://pub.dev" + source: hosted + version: "1.0.2" + web_socket_channel: + dependency: transitive + description: + name: web_socket_channel + sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b + url: "https://pub.dev" + source: hosted + version: "2.4.0" + webkit_inspection_protocol: + dependency: transitive + description: + name: webkit_inspection_protocol + sha256: "67d3a8b6c79e1987d19d848b0892e582dbb0c66c57cc1fef58a177dd2aa2823d" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + yaml: + dependency: transitive + description: + name: yaml + sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" + url: "https://pub.dev" + source: hosted + version: "3.1.2" +sdks: + dart: ">=2.19.0 <3.0.0" diff --git a/dart/phone-number/pubspec.yaml b/dart/phone-number/pubspec.yaml new file mode 100644 index 0000000..dc0a4c5 --- /dev/null +++ b/dart/phone-number/pubspec.yaml @@ -0,0 +1,5 @@ +name: 'phone_number' +environment: + sdk: '>=2.18.0 <3.0.0' +dev_dependencies: + test: '<2.0.0' diff --git a/dart/phone-number/test/phone_number_test.dart b/dart/phone-number/test/phone_number_test.dart new file mode 100644 index 0000000..c0d8503 --- /dev/null +++ b/dart/phone-number/test/phone_number_test.dart @@ -0,0 +1,202 @@ +import 'package:phone_number/phone_number.dart'; +import 'package:test/test.dart'; + +void main() { + final phoneNumber = PhoneNumber(); + + group('PhoneNumber', () { + test('cleans the number', () { + final result = phoneNumber.clean('(223) 456-7890'); + expect(result, equals('2234567890')); + }, skip: false); + + test('cleans numbers with dots', () { + final result = phoneNumber.clean('223.456.7890'); + expect(result, equals('2234567890')); + }, skip: false); + + test('cleans numbers with multiple spaces', () { + final result = phoneNumber.clean('223 456 7890 '); + expect(result, equals('2234567890')); + }, skip: false); + + test('invalid when 9 digits', () { + expect( + () => phoneNumber.clean('123456789'), + throwsA( + isA().having( + (e) => e.message, + 'message', + 'must not be fewer than 10 digits', + ), + ), + ); + }, skip: false); + + test('invalid when 11 digits does not start with a 1', () { + expect( + () => phoneNumber.clean('22234567890'), + throwsA( + isA().having( + (e) => e.message, + 'message', + '11 digits must start with 1', + ), + ), + ); + }, skip: false); + + test('valid when 11 digits and starting with 1', () { + final result = phoneNumber.clean('12234567890'); + expect(result, equals('2234567890')); + }, skip: false); + + test('valid when 11 digits and starting with 1 even with punctuation', () { + final result = phoneNumber.clean('+1 (223) 456-7890'); + expect(result, equals('2234567890')); + }, skip: false); + + test('invalid when more than 11 digits', () { + expect( + () => phoneNumber.clean('321234567890'), + throwsA( + isA().having( + (e) => e.message, + 'message', + 'must not be greater than 11 digits', + ), + ), + ); + }, skip: false); + + test('invalid with letters', () { + expect( + () => phoneNumber.clean('523-abc-7890'), + throwsA( + isA().having( + (e) => e.message, + 'message', + 'letters not permitted', + ), + ), + ); + }, skip: false); + + test('invalid with punctuations', () { + expect( + () => phoneNumber.clean('523-@:!-7890'), + throwsA( + isA().having( + (e) => e.message, + 'message', + 'punctuations not permitted', + ), + ), + ); + }, skip: false); + + test('invalid if area code starts with 0', () { + expect( + () => phoneNumber.clean('(023) 456-7890'), + throwsA( + isA().having( + (e) => e.message, + 'message', + 'area code cannot start with zero', + ), + ), + ); + }, skip: false); + + test('invalid if area code starts with 1', () { + expect( + () => phoneNumber.clean('(123) 456-7890'), + throwsA( + isA().having( + (e) => e.message, + 'message', + 'area code cannot start with one', + ), + ), + ); + }, skip: false); + + test('invalid if exchange code starts with 0', () { + expect( + () => phoneNumber.clean('(223) 056-7890'), + throwsA( + isA().having( + (e) => e.message, + 'message', + 'exchange code cannot start with zero', + ), + ), + ); + }, skip: false); + + test('invalid if exchange code starts with 1', () { + expect( + () => phoneNumber.clean('(223) 156-7890'), + throwsA( + isA().having( + (e) => e.message, + 'message', + 'exchange code cannot start with one', + ), + ), + ); + }, skip: false); + + test('invalid if area code starts with 0 on valid 11-digit number', () { + expect( + () => phoneNumber.clean('1 (023) 456-7890'), + throwsA( + isA().having( + (e) => e.message, + 'message', + 'area code cannot start with zero', + ), + ), + ); + }, skip: false); + + test('invalid if area code starts with 1 on valid 11-digit number', () { + expect( + () => phoneNumber.clean('1 (123) 456-7890'), + throwsA( + isA().having( + (e) => e.message, + 'message', + 'area code cannot start with one', + ), + ), + ); + }, skip: false); + + test('invalid if exchange code starts with 0 on valid 11-digit number', () { + expect( + () => phoneNumber.clean('1 (223) 056-7890'), + throwsA( + isA().having( + (e) => e.message, + 'message', + 'exchange code cannot start with zero', + ), + ), + ); + }, skip: false); + + test('invalid if exchange code starts with 1 on valid 11-digit number', () { + expect( + () => phoneNumber.clean('1 (223) 156-7890'), + throwsA( + isA().having( + (e) => e.message, + 'message', + 'exchange code cannot start with one', + ), + ), + ); + }, skip: false); + }); +}