huck has shown why your regex (correctly!) matches a single space. Here's the approach I would take to a solution. (Note that I am sure there are CPAN modules to do all this much better!) Pay particular attention to adding test cases to the no-match section of tests. I would also add some mixed-case tests to the all-match section.
c:\@Work\Perl\monks>perl -wMstrict -le
"use Test::More 'no_plan';
use Test::NoWarnings;
;;
my $rx_1_3 = qr{ (?i) i{1,3} }xms;
my $rx_1_9 = qr{ (?i) (?: $rx_1_3 | iv | v $rx_1_3? | ix) }xms;
my $rx_1_39 = qr{ (?i) (?: $rx_1_9 | x{1,3} $rx_1_9?) }xms;
;;
my $pat = qr{ [(]? \b $rx_1_39 \b (?: [.] | [)][.]?) [ ] }xms;
;;
use constant ROMAN_1_39 => qw(
i ii iii iv v vi vii viii ix x
xi xii xiii xiv xv xvi xvii xviii xix xx
xxi xxii xxiii xxiv xxv xxvi xxvii xxviii xxix xxx
xxxi xxxii xxxiii xxxiv xxxv xxxvi xxxvii xxxviii xxxix
);
;;
note 'perl version: ', $];
;;
my $test_regex = qr{ \A $pat \z }xms;
note 'test regex: ', $test_regex;
;;
note 'ALL must match';
for my $roman (ROMAN_1_39, map uc, ROMAN_1_39) {
for my $pre ('', '(') {
for my $post (qw/. ) )./) {
my $rs = qq{$pre$roman$post };
ok $rs =~ $test_regex, qq{'$rs'};
}
}
}
;;
note 'NONE shall pass!';
for my $nomatch (ROMAN_1_39, ' ',
qw(iiii ixxxix xxxixi ixxxixi etc),
) {
ok $nomatch !~ $test_regex, qq{'$nomatch'};
}
;;
done_testing;
"
(I won't pollute these sacred spaces with the rather tedious output.)
Give a man a fish: <%-{-{-{-<