exercism-perl5

Repository for my Perl 5 Exercism exercises
git clone git://git.samirparikh.com/exercism-perl5
Log | Files | Refs | README

commit e35bd4e67fe0806a2df1de17c73e968070fc6897
parent c59151f6dc7ff16e5884f08cd55adc1df15781a9
Author: Samir Parikh <noreply@samirparikh.com>
Date:   Fri, 26 Aug 2022 22:10:05 +0000

initial commit

Diffstat:
Aluhn/HELP.md | 36++++++++++++++++++++++++++++++++++++
Aluhn/Luhn.pm | 30++++++++++++++++++++++++++++++
Aluhn/README.md | 88+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aluhn/luhn.t | 171+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 325 insertions(+), 0 deletions(-)

diff --git a/luhn/HELP.md b/luhn/HELP.md @@ -0,0 +1,35 @@ +# Help + +## Running the tests + +There is a Perl 5 script with the extension `.t`, which will be used to test +your solution. You can run through the tests by using the command: + +```bash +`prove .` +``` + +## Submitting your solution + +You can submit your solution using the `exercism submit Luhn.pm` 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 [Perl 5 track's documentation](https://exercism.org/docs/tracks/perl5) +- [Exercism's support channel on gitter](https://gitter.im/exercism/support) +- 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: + +- [/r/perl5](https://www.reddit.com/r/perl5) is the perl5 subreddit. +- [StackOverflow](http://stackoverflow.com/questions/tagged/perl5) 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/luhn/Luhn.pm b/luhn/Luhn.pm @@ -0,0 +1,30 @@ +package Luhn; + +use strict; +use warnings; +use feature qw<say>; + +use Exporter qw<import>; +our @EXPORT_OK = qw<is_luhn_valid>; + +sub is_luhn_valid { + my ($input) = @_; + #print "input was originally '$input'\n"; + $input =~ s/\s+//g; # remove whitespace + #print "input = $input\n"; + + # return false if string is less than 2 digits + return 0 if ( length $input < 2 ); + + # return false if we find a non-decimal character + return 0 if ( $input =~ m/\D/ ); + my @numbers = ( $input =~ m/\d/g ); # split out input into array + print join( ":", @numbers), "\n"; + + # the special variable $#numbers represents the index of the last element + # of the array @numbers + + return undef; +} + +1; diff --git a/luhn/README.md b/luhn/README.md @@ -0,0 +1,87 @@ +# Luhn + +Welcome to Luhn on Exercism's Perl 5 Track. +If you need help running the tests or submitting your code, check out `HELP.md`. + +## Instructions + +Given a number determine whether or not it is valid per the Luhn formula. + +The [Luhn algorithm](https://en.wikipedia.org/wiki/Luhn_algorithm) is +a simple checksum formula used to validate a variety of identification +numbers, such as credit card numbers and Canadian Social Insurance +Numbers. + +The task is to check if a given string is valid. + +## Validating a Number + +Strings of length 1 or less are not valid. Spaces are allowed in the input, +but they should be stripped before checking. All other non-digit characters +are disallowed. + +### Example 1: valid credit card number + +```text +4539 3195 0343 6467 +``` + +The first step of the Luhn algorithm is to double every second digit, +starting from the right. We will be doubling + +```text +4_3_ 3_9_ 0_4_ 6_6_ +``` + +If doubling the number results in a number greater than 9 then subtract 9 +from the product. The results of our doubling: + +```text +8569 6195 0383 3437 +``` + +Then sum all of the digits: + +```text +8+5+6+9+6+1+9+5+0+3+8+3+3+4+3+7 = 80 +``` + +If the sum is evenly divisible by 10, then the number is valid. This number is valid! + +### Example 2: invalid credit card number + +```text +8273 1232 7352 0569 +``` + +Double the second digits, starting from the right + +```text +7253 2262 5312 0539 +``` + +Sum the digits + +```text +7+2+5+3+2+2+6+2+5+3+1+2+0+5+3+9 = 57 +``` + +57 is not evenly divisible by 10, so this number is not valid. + +## Source + +### Created by + +- @bistik + +### Contributed to by + +- @alexkalderimis +- @kytrinyx +- @m-dango +- @pgraemer +- @rfilipo + +### Based on + +The Luhn Algorithm on Wikipedia - http://en.wikipedia.org/wiki/Luhn_algorithm +\ No newline at end of file diff --git a/luhn/luhn.t b/luhn/luhn.t @@ -0,0 +1,171 @@ +#!/usr/bin/env perl +use Test2::V0; +use JSON::PP; +use constant JSON => JSON::PP->new; + +use FindBin qw<$Bin>; +use lib $Bin, "$Bin/local/lib/perl5"; + +use Luhn qw<is_luhn_valid>; + +my @test_cases = do { local $/; @{ JSON->decode(<DATA>) }; }; +plan 19; + +imported_ok qw<is_luhn_valid> or bail_out; + +for my $case (@test_cases) { + is( is_luhn_valid( $case->{input}{value} ), + $case->{expected} + ? T + : DF, + $case->{description} + ); +} + +__DATA__ +[ + { + "description": "single digit strings can not be valid", + "expected": false, + "input": { + "value": "1" + }, + "property": "valid" + }, + { + "description": "a single zero is invalid", + "expected": false, + "input": { + "value": "0" + }, + "property": "valid" + }, + { + "description": "a simple valid SIN that remains valid if reversed", + "expected": true, + "input": { + "value": "059" + }, + "property": "valid" + }, + { + "description": "a simple valid SIN that becomes invalid if reversed", + "expected": true, + "input": { + "value": "59" + }, + "property": "valid" + }, + { + "description": "a valid Canadian SIN", + "expected": true, + "input": { + "value": "055 444 285" + }, + "property": "valid" + }, + { + "description": "invalid Canadian SIN", + "expected": false, + "input": { + "value": "055 444 286" + }, + "property": "valid" + }, + { + "description": "invalid credit card", + "expected": false, + "input": { + "value": "8273 1232 7352 0569" + }, + "property": "valid" + }, + { + "description": "invalid long number with an even remainder", + "expected": false, + "input": { + "value": "1 2345 6789 1234 5678 9012" + }, + "property": "valid" + }, + { + "description": "valid number with an even number of digits", + "expected": true, + "input": { + "value": "095 245 88" + }, + "property": "valid" + }, + { + "description": "valid number with an odd number of spaces", + "expected": true, + "input": { + "value": "234 567 891 234" + }, + "property": "valid" + }, + { + "description": "valid strings with a non-digit added at the end become invalid", + "expected": false, + "input": { + "value": "059a" + }, + "property": "valid" + }, + { + "description": "valid strings with punctuation included become invalid", + "expected": false, + "input": { + "value": "055-444-285" + }, + "property": "valid" + }, + { + "description": "valid strings with symbols included become invalid", + "expected": false, + "input": { + "value": "055# 444$ 285" + }, + "property": "valid" + }, + { + "description": "single zero with space is invalid", + "expected": false, + "input": { + "value": " 0" + }, + "property": "valid" + }, + { + "description": "more than a single zero is valid", + "expected": true, + "input": { + "value": "0000 0" + }, + "property": "valid" + }, + { + "description": "input digit 9 is correctly converted to output digit 9", + "expected": true, + "input": { + "value": "091" + }, + "property": "valid" + }, + { + "description": "using ascii value for non-doubled non-digit isn't allowed", + "expected": false, + "input": { + "value": "055b 444 285" + }, + "property": "valid" + }, + { + "description": "using ascii value for doubled non-digit isn't allowed", + "expected": false, + "input": { + "value": ":9" + }, + "property": "valid" + } +]