aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--challenge-184/duncan-c-white/C/.cbuild2
-rw-r--r--challenge-184/duncan-c-white/C/Makefile16
-rw-r--r--challenge-184/duncan-c-white/C/README5
-rw-r--r--challenge-184/duncan-c-white/C/args.c207
-rw-r--r--challenge-184/duncan-c-white/C/args.h11
-rw-r--r--challenge-184/duncan-c-white/C/ch-1.c68
-rw-r--r--challenge-184/duncan-c-white/C/ch-2.c140
-rwxr-xr-xchallenge-184/duncan-c-white/C/ch-2.pl54
-rw-r--r--challenge-184/duncan-c-white/README79
-rwxr-xr-xchallenge-184/duncan-c-white/perl/ch-1.pl57
-rwxr-xr-xchallenge-184/duncan-c-white/perl/ch-2.pl54
11 files changed, 633 insertions, 60 deletions
diff --git a/challenge-184/duncan-c-white/C/.cbuild b/challenge-184/duncan-c-white/C/.cbuild
index 624a95ebfb..a14ec76520 100644
--- a/challenge-184/duncan-c-white/C/.cbuild
+++ b/challenge-184/duncan-c-white/C/.cbuild
@@ -1,4 +1,4 @@
-BUILD = ch-1
+BUILD = ch-1 ch-2
CFLAGS = -Wall -g
#LDFLAGS = -lm
#CFLAGS = -g
diff --git a/challenge-184/duncan-c-white/C/Makefile b/challenge-184/duncan-c-white/C/Makefile
new file mode 100644
index 0000000000..8d85c7d16d
--- /dev/null
+++ b/challenge-184/duncan-c-white/C/Makefile
@@ -0,0 +1,16 @@
+# Makefile rules generated by CB
+CC = gcc
+CFLAGS = -Wall -g
+BUILD = ch-1 ch-2
+
+all: $(BUILD)
+
+clean:
+ /bin/rm -f $(BUILD) *.o core a.out
+
+args.o: args.c
+ch-1: ch-1.o args.o
+ch-1.o: ch-1.c args.h
+ch-2: ch-2.o args.o
+ch-2.o: ch-2.c args.h
+
diff --git a/challenge-184/duncan-c-white/C/README b/challenge-184/duncan-c-white/C/README
new file mode 100644
index 0000000000..32275a43e9
--- /dev/null
+++ b/challenge-184/duncan-c-white/C/README
@@ -0,0 +1,5 @@
+Thought I'd also have a go at translating ch-1.pl and ch-2.pl into C..
+
+Both produce identical (non-debugging) output to my Perl originals.
+
+Both use the command-line argument processing module args.[ch].
diff --git a/challenge-184/duncan-c-white/C/args.c b/challenge-184/duncan-c-white/C/args.c
new file mode 100644
index 0000000000..d4a2d38b9a
--- /dev/null
+++ b/challenge-184/duncan-c-white/C/args.c
@@ -0,0 +1,207 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+
+
+bool debug = false;
+
+
+// process_flag_noarg( name, argc, argv );
+// Process the -d flag, and check that there are no
+// remaining arguments.
+void process_flag_noarg( char *name, int argc, char **argv )
+{
+ int arg=1;
+ if( argc>1 && strcmp( argv[arg], "-d" ) == 0 )
+ {
+ debug = true;
+ arg++;
+ }
+
+ int left = argc-arg;
+ if( left != 0 )
+ {
+ fprintf( stderr, "Usage: %s [-d]\n", name );
+ exit(1);
+ }
+}
+
+
+// int argno = process_flag_n_args( name, argc, argv, n, argmsg );
+// Process the -d flag, and check that there are exactly
+// n remaining arguments, return the index position of the first
+// argument. If not, generate a fatal Usage error using the argmsg.
+//
+int process_flag_n_args( char *name, int argc, char **argv, int n, char *argmsg )
+{
+ int arg=1;
+ if( argc>1 && strcmp( argv[arg], "-d" ) == 0 )
+ {
+ debug = true;
+ arg++;
+ }
+
+ int left = argc-arg;
+ if( left != n )
+ {
+ fprintf( stderr, "Usage: %s [-d] %s\n Exactly %d "
+ "arguments needed\n", name, argmsg, n );
+ exit(1);
+ }
+ return arg;
+}
+
+
+// int argno = process_flag_n_m_args( name, argc, argv, min, max, argmsg );
+// Process the -d flag, and check that there are between
+// min and max remaining arguments, return the index position of the first
+// argument. If not, generate a fatal Usage error using the argmsg.
+//
+int process_flag_n_m_args( char *name, int argc, char **argv, int min, int max, char *argmsg )
+{
+ int arg=1;
+ if( argc>1 && strcmp( argv[arg], "-d" ) == 0 )
+ {
+ debug = true;
+ arg++;
+ }
+
+ int left = argc-arg;
+ if( left < min || left > max )
+ {
+ fprintf( stderr, "Usage: %s [-d] %s\n Between %d and %d "
+ "arguments needed\n", name, argmsg, min, max );
+ exit(1);
+ }
+ return arg;
+}
+
+
+// process_onenumarg_default( name, argc, argv, defvalue, &n );
+// Process the -d flag, and check that there is a single
+// remaining numeric argument (or no arguments, in which case
+// we use the defvalue), putting it into n
+void process_onenumarg_default( char *name, int argc, char **argv, int defvalue, int *n )
+{
+ char argmsg[100];
+ sprintf( argmsg, "[int default %d]", defvalue );
+ int arg = process_flag_n_m_args( name, argc, argv, 0, 1, argmsg );
+
+ *n = arg == argc ? defvalue : atoi( argv[arg] );
+}
+
+
+// process_onenumarg( name, argc, argv, &n );
+// Process the -d flag, and check that there is a single
+// remaining numeric argument, putting it into n
+void process_onenumarg( char *name, int argc, char **argv, int *n )
+{
+ int arg = process_flag_n_args( name, argc, argv, 1, "int" );
+
+ // argument is in argv[arg]
+ *n = atoi( argv[arg] );
+}
+
+
+// process_twonumargs( name, argc, argv, &m, &n );
+// Process the -d flag, and check that there are 2
+// remaining numeric arguments, putting them into m and n
+void process_twonumargs( char *name, int argc, char **argv, int *m, int *n )
+{
+ int arg = process_flag_n_args( name, argc, argv, 2, "int" );
+
+ // arguments are in argv[arg] and argv[arg+1]
+ *m = atoi( argv[arg++] );
+ *n = atoi( argv[arg] );
+}
+
+
+// process_twostrargs() IS DEPRECATED: use process_flag_n_m_args() instead
+
+
+// int arr[100];
+// int nel = process_listnumargs( name, argc, argv, arr, 100 );
+// Process the -d flag, and check that there are >= 2
+// remaining numeric arguments, putting them into arr[0..nel-1]
+// and returning nel.
+int process_listnumargs( char *name, int argc, char **argv, int *arr, int maxel )
+{
+ int arg=1;
+ if( argc>1 && strcmp( argv[arg], "-d" ) == 0 )
+ {
+ debug = true;
+ arg++;
+ }
+
+ int left = argc-arg;
+ if( left < 2 )
+ {
+ fprintf( stderr, "Usage: %s [-d] list_of_numeric_args\n", name );
+ exit(1);
+ }
+ if( left > maxel )
+ {
+ fprintf( stderr, "%s: more than %d args\n", name, maxel );
+ exit(1);
+ }
+
+ // elements are in argv[arg], argv[arg+1]...
+
+ if( debug )
+ {
+ printf( "debug: remaining arguments are in arg=%d, "
+ "firstn=%s, secondn=%s..\n",
+ arg, argv[arg], argv[arg+1] );
+ }
+
+ int nel = 0;
+ for( int i=arg; i<argc; i++ )
+ {
+ arr[nel++] = atoi( argv[i] );
+ }
+ arr[nel] = -1;
+ return nel;
+}
+
+
+//
+// bool isint = check_unsigned_int( char *val, int *n );
+// Given an string val, check that there's an unsigned integer
+// in it (after optional whitespace). If there is a valid
+// unsigned integer value, store that integer value in *n and
+// return true; otherwise return false (and don't alter *n).
+bool check_unsigned_int( char *val, int *n )
+{
+ // skip whitespace in val
+ char *p;
+ for( p=val; isspace(*p); p++ )
+ {
+ /*EMPTY*/
+ }
+ if( ! isdigit(*p) ) return false;
+ *n = atoi(p);
+ return true;
+}
+
+
+//
+// bool ok = check_unsigned_real( char *val, double *n );
+// Given an string val, check that there's an unsigned real
+// in it (after optional whitespace). If there is a valid
+// unsigned real value, store that value in *n and
+// return true; otherwise return false (and don't alter *n).
+bool check_unsigned_real( char *val, double *n )
+{
+ // skip whitespace in val
+ char *p;
+ for( p=val; isspace(*p); p++ )
+ {
+ /*EMPTY*/
+ }
+ if( ! isdigit(*p) ) return false;
+ *n = atof(p);
+ return true;
+}
diff --git a/challenge-184/duncan-c-white/C/args.h b/challenge-184/duncan-c-white/C/args.h
new file mode 100644
index 0000000000..8844a8f9c4
--- /dev/null
+++ b/challenge-184/duncan-c-white/C/args.h
@@ -0,0 +1,11 @@
+extern bool debug;
+
+extern void process_flag_noarg( char * name, int argc, char ** argv );
+extern int process_flag_n_args( char * name, int argc, char ** argv, int n, char * argmsg );
+extern int process_flag_n_m_args( char * name, int argc, char ** argv, int min, int max, char * argmsg );
+extern void process_onenumarg_default( char * name, int argc, char ** argv, int defvalue, int * n );
+extern void process_onenumarg( char * name, int argc, char ** argv, int * n );
+extern void process_twonumargs( char * name, int argc, char ** argv, int * m, int * n );
+extern int process_listnumargs( char * name, int argc, char ** argv, int * arr, int maxel );
+extern bool check_unsigned_int( char * val, int * n );
+extern bool check_unsigned_real( char * val, double * n );
diff --git a/challenge-184/duncan-c-white/C/ch-1.c b/challenge-184/duncan-c-white/C/ch-1.c
new file mode 100644
index 0000000000..3996388c8b
--- /dev/null
+++ b/challenge-184/duncan-c-white/C/ch-1.c
@@ -0,0 +1,68 @@
+//
+// Task 1: Sequence Number
+//
+// C version.
+//
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include "args.h"
+
+
+//
+// seqno( strbuf );
+// Given a writable string in the format aa9999 i.e. first 2 characters
+// can be anything 'a-z' followed by 4 digits '0-9',
+// replace the first two characters with sequence starting
+// with '00', '01', '02' etc.
+//
+static void seqno( char *strbuf )
+{
+ static int seqno = 0;
+ if( strlen(strbuf)!=6 || !isalpha(strbuf[0]) || !isalpha(strbuf[1])
+ || !isdigit(strbuf[2]) || !isdigit(strbuf[3]) || ! isdigit(strbuf[4])
+ || !isdigit(strbuf[5]) )
+ {
+ fprintf( stderr, "bad format %s: not lldddd\n", strbuf );
+ exit(1);
+ }
+ int x = seqno++;
+ strbuf[0] = '0' + x/10;
+ strbuf[1] = '0' + x%10;
+}
+
+
+int main( int argc, char **argv )
+{
+ int argno = process_flag_n_m_args( "sequence-number", argc, argv,
+ 1, 100000, "list of strings" );
+
+ int numarrays = argc-argno;
+ if( debug )
+ {
+ printf( "debug: numarrays=%d\n", numarrays );
+ }
+
+ int i;
+ bool isfirst=true;
+ for( i=argno; i<argc; i++ )
+ {
+ if( !isfirst )
+ {
+ putchar(',');
+ }
+ isfirst=false;
+ char arg[10];
+ strcpy( arg, argv[i] );
+ seqno( arg );
+ printf( "%s", arg );
+ }
+ putchar('\n');
+
+ return 0;
+}
diff --git a/challenge-184/duncan-c-white/C/ch-2.c b/challenge-184/duncan-c-white/C/ch-2.c
new file mode 100644
index 0000000000..1a56dc6478
--- /dev/null
+++ b/challenge-184/duncan-c-white/C/ch-2.c
@@ -0,0 +1,140 @@
+//
+// Task 2: Split Array
+//
+// C version.
+//
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include "args.h"
+
+
+//
+// process_one_el( el, outp, wantnum, appanyp );
+// Given an element string argument (el), which should be EITHER be a
+// number or a letter/word, and an output pointer outp, and a boolean
+// (wantnum) telling us whether to search for numbers or letters, and
+// a ptr-to-a-boolean (appanyp) which says whether or not we've yet
+// appended anything to outp, check whether the element should
+// be included, and append it to outp if it is, modifying *appanyp.
+//
+static void process_one_el( char *el, char *outp, bool wantnum, bool *anyp )
+{
+ if( debug )
+ {
+ printf( "debug: pel: el=%s\n", el );
+ }
+
+ if( ! (wantnum && isdigit(*el)) && ! ( !wantnum && isalpha(*el)) )
+ {
+ return;
+ }
+
+ for( ; *outp; outp++ ) /*EMPTY*/;
+
+ if( debug )
+ {
+ printf( "debug: pel: good el=%s, outp=%s\n", el, outp );
+ }
+
+ if( ! *anyp )
+ {
+ *outp++ = '[';
+ *anyp = true;
+ } else
+ {
+ *outp++ = ',';
+ }
+ strcpy( outp, el );
+}
+
+
+//
+// onepass( arg, outp, wantnum );
+// Given a modifiable string argument (arg), which should be a
+// space-sep-values-string, and an output pointer outp, and a boolean
+// (wantnum) telling us whether to search for numbers (if wantnum)
+// or letters (if !wantnum), append well formatted lists of such elements
+// from arg to outp.
+//
+static void onepass( char *arg, char *outp, bool wantnum )
+{
+ bool appany = false; // have we yet appended anything to outp?
+
+ char *p;
+ char *end;
+ for( p=arg; (end=strchr(p,' '))!= NULL; p=end+1 )
+ {
+ *end = '\0';
+ process_one_el( p, outp, wantnum, &appany );
+ *end = ' ';
+ }
+ process_one_el( p, outp, wantnum, &appany );
+ if( appany )
+ {
+ strcat( outp, "], " );
+ }
+}
+
+
+//
+// process( char *arg, char *letp, char *nump );
+// Given a string argument (arg), which should be a csv-string
+// and a letter-string-pointer (letp) and a number-string-pointer (nump)
+// append well formatted lists of letters in arg to letp, and
+// append well formatted lists of numbers in arg to letp.
+//
+static void process( char *arg, char *letp, char *nump )
+{
+ // convert commas to spaces
+ for( char *p=arg; *p; p++ )
+ {
+ if( *p == ',' ) *p = ' ';
+ }
+
+ // append any numbers in arg to nump
+ onepass( arg, nump, true );
+
+ // append any letters in arg to letp
+ onepass( arg, letp, false );
+}
+
+
+int main( int argc, char **argv )
+{
+ int argno = process_flag_n_m_args( "split-array", argc, argv,
+ 1, 100000, "array of csv-strings" );
+
+ int numstrings = argc-argno;
+ if( debug )
+ {
+ printf( "debug: numstrings=%d\n", numstrings );
+ }
+
+ char letstr[1024];
+ char numstr[1024];
+ strcpy( letstr, "" );
+ strcpy( numstr, "" );
+
+ char *lp = letstr;
+ char *np = numstr;
+
+ int i;
+ for( i=argno; i<argc; i++ )
+ {
+ process( argv[i], lp, np );
+ lp += strlen(lp);
+ np += strlen(np);
+ }
+ numstr[strlen(numstr)-2] = '\0';
+ letstr[strlen(letstr)-2] = '\0';
+
+ printf( "Output: [%s] and [%s]\n", numstr, letstr );
+
+ return 0;
+}
diff --git a/challenge-184/duncan-c-white/C/ch-2.pl b/challenge-184/duncan-c-white/C/ch-2.pl
new file mode 100755
index 0000000000..70c0d83b3f
--- /dev/null
+++ b/challenge-184/duncan-c-white/C/ch-2.pl
@@ -0,0 +1,54 @@
+#!/usr/bin/perl
+#
+# Task 2: Split Array
+#
+# You are given list of strings containing 0-9 and a-z separated by space only.
+# Write a script to split the data into two arrays, one for integers and
+# one for alphabets only.
+#
+# Example 1
+#
+# Input: @list = ( 'a 1 2 b 0', '3 c 4 d')
+# Output: [[1,2,0], [3,4]] and [['a','b'], ['c','d']]
+#
+# Example 2
+#
+# Input: @list = ( '1 2', 'p q r', 's 3', '4 5 t')
+# Output: [[1,2], [3], [4,5]] and [['p','q','r'], ['s'], ['t']]
+#
+# MY NOTES: Also seems pretty simple.
+#
+# GUEST LANGUAGE: As a bonus, I also had a go at translating ch-2.pl
+# into C (look in the C directory for that).
+#
+
+use strict;
+use warnings;
+use feature 'say';
+use Getopt::Long;
+use Data::Dumper;
+
+my $debug=0;
+die "Usage: split-array [--debug] 'csv_string'+\n"
+ unless GetOptions( "debug"=>\$debug ) && @ARGV>0;
+
+my @num;
+my @let;
+
+foreach my $list (@ARGV)
+{
+ $list =~ tr/,/ /;
+ my @x = split(/\s+/,$list);
+ my @a = grep { /\d/ } @x;
+ push @num, [ @a ] if @a;
+ @a = grep { /[a-z]/ } @x;
+ push @let, [ @a ] if @a;
+}
+
+#say Dumper(\@let);
+#say Dumper(\@num);
+
+my $letstr = "[". join( ', ', map { "[".join(',',@$_)."]" } @let ) . "]";
+my $numstr = "[". join( ', ', map { "[".join(',',@$_)."]" } @num ) . "]";
+
+say "Output: $numstr and $letstr";
diff --git a/challenge-184/duncan-c-white/README b/challenge-184/duncan-c-white/README
index 8b1fb7e81b..2cd8d35c5f 100644
--- a/challenge-184/duncan-c-white/README
+++ b/challenge-184/duncan-c-white/README
@@ -1,82 +1,43 @@
-Task 1: Unique Array
+Task 1: Sequence Number
-You are given list of arrayrefs.
-Write a script to remove the duplicate arrayrefs from the given list.
+You are given list of strings in the format aa9999 i.e. first 2 characters
+can be anything 'a-z' followed by 4 digits '0-9'.
+Write a script to replace the first two characters with sequence starting
+with '00', '01', '02' etc.
Example 1
-Input: @list = ([1,2], [3,4], [5,6], [1,2])
-Output: ([1,2], [3,4], [5,6])
+ Input: @list = ( 'ab1234', 'cd5678', 'ef1342')
+ Output: ('001234', '015678', '021342')
Example 2
-Input: @list = ([9,1], [3,7], [2,5], [2,5])
-Output: ([9, 1], [3,7], [2,5])
+ Input: @list = ( 'pq1122', 'rs3334')
+ Output: ('001122', '013334')
-MY NOTES: nice and easy, only challenge is how to store a representation
-of an entire array as a hash key: obvious option is to join(',',@items)
+MY NOTES: nice and easy. Trivial in fact.
GUEST LANGUAGE: As a bonus, I also had a go at implementing ch-1.pl
-into C (look in the C directory for that). It's not a direct translation
-of the Perl solution because that involves sets of joined strings, instead
-it does it the obvious low-tech way: finding duplicate arrays and deleting
-them.
+into C (look in the C directory for that).
-Task 2: Date Difference
+Task 2: Split Array
-You are given two dates, $date1 and $date2 in the format YYYY-MM-DD.
-Write a script to find the difference between the given dates in terms on years and days only.
+You are given list of strings containing 0-9 and a-z separated by space only.
+Write a script to split the data into two arrays, one for integers and
+one for alphabets only.
Example 1
-Input: $date1 = '2019-02-10'
- $date2 = '2022-11-01'
-Output: 3 years 264 days
+ Input: @list = ( 'a 1 2 b 0', '3 c 4 d')
+ Output: [[1,2,0], [3,4]] and [['a','b'], ['c','d']]
Example 2
-Input: $date1 = '2020-09-15'
- $date2 = '2022-03-29'
-Output: 1 year 195 days
-
-Example 3
-
-Input: $date1 = '2019-12-31'
- $date2 = '2020-01-01'
-Output: 1 day
-
-Example 4
-
-Input: $date1 = '2019-12-01'
- $date2 = '2019-12-31'
-Output: 30 days
-
-Example 5
-
-Input: $date1 = '2019-12-31'
- $date2 = '2020-12-31'
-Output: 1 year
-
-Example 6
-
-Input: $date1 = '2019-12-31'
- $date2 = '2021-12-31'
-Output: 2 years
-
-Example 7
-
-Input: $date1 = '2020-09-15'
- $date2 = '2021-09-16'
-Output: 1 year 1 day
-
-Example 8
-
-Input: $date1 = '2019-09-15'
- $date2 = '2021-09-16'
-Output: 2 years 1 day
+ Input: @list = ( '1 2', 'p q r', 's 3', '4 5 t')
+ Output: [[1,2], [3], [4,5]] and [['p','q','r'], ['s'], ['t']]
-MY NOTES: Should be a simple task for Date::Simple or Date::Manup.
+MY NOTES: Also seems pretty simple.
GUEST LANGUAGE: As a bonus, I also had a go at translating ch-2.pl
into C (look in the C directory for that).
diff --git a/challenge-184/duncan-c-white/perl/ch-1.pl b/challenge-184/duncan-c-white/perl/ch-1.pl
new file mode 100755
index 0000000000..a3067e1622
--- /dev/null
+++ b/challenge-184/duncan-c-white/perl/ch-1.pl
@@ -0,0 +1,57 @@
+#!/usr/bin/perl
+#
+# Task 1: Sequence Number
+#
+# You are given list of strings in the format aa9999 i.e. first 2 characters
+# can be anything 'a-z' followed by 4 digits '0-9'.
+# Write a script to replace the first two characters with sequence starting
+# with '00', '01', '02' etc.
+#
+# Example 1
+#
+# Input: @list = ( 'ab1234', 'cd5678', 'ef1342')
+# Output: ('001234', '015678', '021342')
+#
+# Example 2
+#
+# Input: @list = ( 'pq1122', 'rs3334')
+# Output: ('001122', '013334')
+#
+# MY NOTES: nice and easy. Trivial in fact.
+#
+# GUEST LANGUAGE: As a bonus, I also had a go at implementing ch-1.pl
+# into C (look in the C directory for that).
+#
+
+use strict;
+use warnings;
+use feature 'say';
+use feature 'state';
+use Getopt::Long;
+use Data::Dumper;
+
+
+my $debug=0;
+die "Usage: sequence-number [--debug] string+\n"
+ unless GetOptions( "debug"=>\$debug ) && @ARGV>0;
+
+#
+# my $seqstr = seqno( $str );
+# Given a string in the format aa9999 i.e. first 2 characters
+# can be anything 'a-z' followed by 4 digits '0-9',
+# replace the first two characters with sequence starting
+# with '00', '01', '02' etc.
+#
+sub seqno
+{
+ my( $str ) = @_;
+ state $seqno = 0;
+ die "bad format $str: not lldddd\n" unless $str =~ /^(\w\w)(\d\d\d\d)$/;
+ $str = sprintf( "%02d%s", $seqno++, $2 );
+ return $str;
+}
+
+
+my @list = @ARGV;
+
+say join( ',', map { seqno($_) } @list );
diff --git a/challenge-184/duncan-c-white/perl/ch-2.pl b/challenge-184/duncan-c-white/perl/ch-2.pl
new file mode 100755
index 0000000000..70c0d83b3f
--- /dev/null
+++ b/challenge-184/duncan-c-white/perl/ch-2.pl
@@ -0,0 +1,54 @@
+#!/usr/bin/perl
+#
+# Task 2: Split Array
+#
+# You are given list of strings containing 0-9 and a-z separated by space only.
+# Write a script to split the data into two arrays, one for integers and
+# one for alphabets only.
+#
+# Example 1
+#
+# Input: @list = ( 'a 1 2 b 0', '3 c 4 d')
+# Output: [[1,2,0], [3,4]] and [['a','b'], ['c','d']]
+#
+# Example 2
+#
+# Input: @list = ( '1 2', 'p q r', 's 3', '4 5 t')
+# Output: [[1,2], [3], [4,5]] and [['p','q','r'], ['s'], ['t']]
+#
+# MY NOTES: Also seems pretty simple.
+#
+# GUEST LANGUAGE: As a bonus, I also had a go at translating ch-2.pl
+# into C (look in the C directory for that).
+#
+
+use strict;
+use warnings;
+use feature 'say';
+use Getopt::Long;
+use Data::Dumper;
+
+my $debug=0;
+die "Usage: split-array [--debug] 'csv_string'+\n"
+ unless GetOptions( "debug"=>\$debug ) && @ARGV>0;
+
+my @num;
+my @let;
+
+foreach my $list (@ARGV)
+{
+ $list =~ tr/,/ /;
+ my @x = split(/\s+/,$list);
+ my @a = grep { /\d/ } @x;
+ push @num, [ @a ] if @a;
+ @a = grep { /[a-z]/ } @x;
+ push @let, [ @a ] if @a;
+}
+
+#say Dumper(\@let);
+#say Dumper(\@num);
+
+my $letstr = "[". join( ', ', map { "[".join(',',@$_)."]" } @let ) . "]";
+my $numstr = "[". join( ', ', map { "[".join(',',@$_)."]" } @num ) . "]";
+
+say "Output: $numstr and $letstr";