Skip to content

Commit 0082df4

Browse files
committed
Added bin/random-string
1 parent eaa5c17 commit 0082df4

File tree

5 files changed

+486
-1
lines changed

5 files changed

+486
-1
lines changed

MANIFEST

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1+
bin/random-string
12
lib/Data/Random/String/Matches.pm
23
LICENSE
34
Makefile.PL
45
MANIFEST This list of files
56
README.md
67
t/30-basics.t
78
t/40-advanced.t
9+
t/cli.t
810
t/eof.t
911
t/eol.t
1012
t/generate.t

Makefile.PL

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@ WriteMakefile(
2525
PL_FILES => {},
2626
CONFIGURE_REQUIRES => {
2727
'ExtUtils::MakeMaker' => 6.64, # Minimum version for TEST_REQUIRES
28-
}, TEST_REQUIRES => {
28+
},
29+
EXE_FILES => ['bin/random-string'],
30+
TEST_REQUIRES => {
2931
'Test::Compile' => 0,
3032
'Test::DescribeMe' => 0,
3133
'Test::Most' => 0,

bin/random-string

Lines changed: 297 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,297 @@
1+
#!/usr/bin/env perl
2+
3+
use strict;
4+
use warnings;
5+
use Getopt::Long qw(:config no_ignore_case);
6+
use Pod::Usage;
7+
use Data::Random::String::Matches;
8+
9+
our $VERSION = '0.01';
10+
11+
# Parse command line options
12+
my %opts = (
13+
count => 1,
14+
length => undef,
15+
smart => 0,
16+
separator => "\n",
17+
help => 0,
18+
man => 0,
19+
version => 0,
20+
examples => 0,
21+
);
22+
23+
GetOptions(
24+
'count|c=i' => \$opts{count},
25+
'length|l=i' => \$opts{length},
26+
'smart|s' => \$opts{smart},
27+
'separator|S=s' => \$opts{separator},
28+
'help|h|?' => \$opts{help},
29+
'man|m' => \$opts{man},
30+
'version|v' => \$opts{version},
31+
'examples|e' => \$opts{examples},
32+
) or pod2usage(2);
33+
34+
# Handle special options
35+
if ($opts{version}) {
36+
print "random-string version $VERSION\n";
37+
exit 0;
38+
}
39+
40+
pod2usage(1) if $opts{help};
41+
pod2usage(-exitval => 0, -verbose => 2) if $opts{man};
42+
43+
if ($opts{examples}) {
44+
show_examples();
45+
exit 0;
46+
}
47+
48+
# Get the pattern from command line
49+
my $pattern = shift @ARGV;
50+
51+
unless (defined $pattern) {
52+
print STDERR "Error: Pattern required\n\n";
53+
pod2usage(1);
54+
}
55+
56+
# Validate options
57+
if ($opts{count} < 1) {
58+
die 'Error: count must be at least 1';
59+
}
60+
61+
# Decode escape sequences in separator
62+
$opts{separator} =~ s/\\n/\n/g;
63+
$opts{separator} =~ s/\\t/\t/g;
64+
$opts{separator} =~ s/\\r/\r/g;
65+
$opts{separator} =~ s/\\0/\0/g;
66+
67+
# Create generator
68+
my $gen = eval {
69+
Data::Random::String::Matches->new($pattern, $opts{length});
70+
};
71+
72+
if ($@) {
73+
die "Error creating generator: $@";
74+
}
75+
76+
# Generate strings
77+
my @results;
78+
for (1 .. $opts{count}) {
79+
my $str = eval {
80+
$opts{smart} ? $gen->generate_smart() : $gen->generate();
81+
};
82+
83+
if ($@) {
84+
die "Error generating string: $@";
85+
}
86+
87+
push @results, $str;
88+
}
89+
90+
# Output results
91+
print join($opts{separator}, @results);
92+
print "\n" unless $opts{separator} =~ /\n$/;
93+
94+
exit 0;
95+
96+
sub show_examples {
97+
print <<'EXAMPLES';
98+
Examples:
99+
100+
# Generate a single 4-digit number
101+
random-string '\d{4}'
102+
103+
# Generate 10 API keys
104+
random-string 'AIza[0-9A-Za-z_-]{35}' --count 10
105+
106+
# Generate 5 email addresses
107+
random-string '[a-z]{5,10}@[a-z]{5,10}\.com' -c 5
108+
109+
# Generate phone numbers with custom separator
110+
random-string '\d{3}-\d{3}-\d{4}' -c 3 -S ', '
111+
112+
# Generate uppercase letters (3 characters)
113+
random-string '[A-Z]{3}'
114+
115+
# Generate password-like strings
116+
random-string '[A-Za-z0-9!@#$%]{16}' -c 5
117+
118+
# Generate UUID-like strings
119+
random-string '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}'
120+
121+
# Use alternation
122+
random-string '(cat|dog|bird)' -c 10
123+
124+
# Use backreferences (repeating pattern)
125+
random-string '(\w{3})-\1' -c 5
126+
127+
# Generate credit card test numbers
128+
random-string '4\d{15}' -c 3
129+
130+
# Use smart mode for complex patterns (faster)
131+
random-string '[A-Z]{3}\d{4}' -c 100 --smart
132+
133+
Common patterns:
134+
\d{4} - 4-digit PIN
135+
[A-Z]{2}\d{3} - License plate style
136+
\d{3}-\d{3}-\d{4} - Phone number
137+
[a-z]+@[a-z]+\.com - Simple email
138+
[A-Fa-f0-9]{32} - MD5 hash
139+
[A-Za-z0-9]{20} - Random token
140+
(foo|bar|baz) - One of three options
141+
(\w{4})-\1 - Repeated pattern
142+
143+
EXAMPLES
144+
}
145+
146+
__END__
147+
148+
=head1 NAME
149+
150+
random-string - Generate random strings matching a regular expression
151+
152+
=head1 SYNOPSIS
153+
154+
random-string [options] PATTERN
155+
156+
Options:
157+
-c, --count N Generate N strings (default: 1)
158+
-l, --length N Set length for fallback generation (default: 10)
159+
-s, --smart Use smart generation only (faster)
160+
-S, --separator STR Separator between outputs (default: newline)
161+
-e, --examples Show usage examples
162+
-h, --help Show brief help
163+
-m, --man Show full manual
164+
-v, --version Show version
165+
166+
=head1 DESCRIPTION
167+
168+
B<random-string> generates random strings that match a given regular expression
169+
pattern. It supports most common regex features including character classes,
170+
quantifiers, groups, alternation, and backreferences.
171+
172+
The pattern should be a valid Perl regular expression. The tool will generate
173+
random strings that match the pattern.
174+
175+
=head1 OPTIONS
176+
177+
=over 4
178+
179+
=item B<-c, --count> N
180+
181+
Generate N random strings. Default is 1.
182+
183+
=item B<-l, --length> N
184+
185+
Set the length for fallback random generation. When the smart parser can't
186+
handle a pattern, it falls back to generating random strings of this length
187+
until one matches. Default is 10.
188+
189+
=item B<-s, --smart>
190+
191+
Use only the smart generation method. This parses the regex and builds matching
192+
strings directly, which is much faster for complex patterns. However, it may
193+
not handle all edge cases.
194+
195+
=item B<-S, --separator> STRING
196+
197+
String to use between multiple outputs. Default is newline. Supports escape
198+
sequences: \n (newline), \t (tab), \r (carriage return).
199+
200+
=item B<-e, --examples>
201+
202+
Show comprehensive usage examples and exit.
203+
204+
=item B<-h, -?, --help>
205+
206+
Print a brief help message and exit.
207+
208+
=item B<-m, --man>
209+
210+
Print the full manual page and exit.
211+
212+
=item B<-v, --version>
213+
214+
Print version information and exit.
215+
216+
=back
217+
218+
=head1 SUPPORTED REGEX FEATURES
219+
220+
=head2 Character Classes
221+
222+
[a-z] Lowercase letters
223+
[A-Z] Uppercase letters
224+
[0-9] Digits
225+
[abc] Specific characters
226+
[^a-z] Negated class
227+
228+
=head2 Escape Sequences
229+
230+
\d Digit [0-9]
231+
\w Word character [a-zA-Z0-9_]
232+
\s Whitespace
233+
\D Non-digit
234+
\W Non-word character
235+
\t \n \r Tab, newline, carriage return
236+
237+
=head2 Quantifiers
238+
239+
{n} Exactly n times
240+
{n,m} Between n and m times
241+
{n,} At least n times
242+
+ One or more
243+
* Zero or more
244+
? Zero or one
245+
246+
=head2 Groups and Alternation
247+
248+
(...) Capturing group
249+
(?:...) Non-capturing group
250+
| Alternation (cat|dog)
251+
\1 \2 Backreferences
252+
253+
=head2 Other
254+
255+
. Any character
256+
^ Start anchor (stripped)
257+
$ End anchor (stripped)
258+
259+
=head1 EXAMPLES
260+
261+
Generate a 4-digit PIN:
262+
263+
random-string '\d{4}'
264+
265+
Generate 10 license plate style codes:
266+
267+
random-string '[A-Z]{3}\d{4}' --count 10
268+
269+
Generate email addresses:
270+
271+
random-string '[a-z]{5,10}@(gmail|yahoo|hotmail)\.com' -c 5
272+
273+
Generate with custom separator (comma-space):
274+
275+
random-string '[A-Z]{3}' -c 5 -S ', '
276+
277+
Generate API keys using smart mode:
278+
279+
random-string 'AIza[0-9A-Za-z_-]{35}' -c 100 --smart
280+
281+
Generate patterns with repetition:
282+
283+
random-string '(\w{4})-\1' -c 3
284+
285+
=head1 EXIT STATUS
286+
287+
Returns 0 on success, non-zero on error.
288+
289+
=head1 AUTHOR
290+
291+
Part of Data::Random::String::Matches distribution.
292+
293+
=head1 SEE ALSO
294+
295+
L<Data::Random::String::Matches>
296+
297+
=cut

lib/Data/Random/String/Matches.pm

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -573,6 +573,7 @@ sub create_random_string
573573
{
574574
my $class = shift;
575575
my $params = Params::Get::get_params(undef, @_);
576+
576577
my $regex = $params->{'regex'};
577578
my $length = $params->{'length'};
578579

0 commit comments

Comments
 (0)