This article is part of the article series "Perl One-Liners Explained."
<- previous article next article ->
Perl One Liners

This is the fourth part of a nine-part article on famous Perl one-liners. In this part I will create various one-liners for string and array creation. See part one for introduction of the series.

Famous Perl one-liners is my attempt to create "perl1line.txt" that is similar to "awk1line.txt" and "sed1line.txt" that have been so popular among Awk and Sed programmers.

The article on famous Perl one-liners will consist of nine parts:

I decided that there will be two new parts in this series. The most powerful feature in Perl is its regular expressions, therefore I will write a part on "Handy Perl regular expressions." I also decided to publish an e-book after I am done with the series, so that will be the last part of this series. Subscribe to my blog to know when that happens!

Awesome news: I have written an e-book based on this article series. Check it out:

I also updated the previous part on calculations with 14 new one-liners on finding values of constants pi and e, doing date calculations, finding factorial, greatest common divisor, least common multiple, generating random numbers, generating permutations, finding power sets and doing some IP address conversions.

Here are today's one-liners:

String Creation and Array Creation

49. Generate and print the alphabet.

perl -le 'print a..z'

This one-liner prints all the letters from a to z as abcdefghijklmnopqrstuvwxyz. The letters are generated by the range operator ... The range operator, when used in the list context (which is forced here by print) on strings, uses the magical auto-increment algorithm that advances the string to the next character. So in this one-liner the auto-increment algorithm on the range a..z produces all the letters from a to z.

I really golfed this one-liner. If you used strict it would not work because of barewords a and z. Semantically more correct version is this:

perl -le 'print ("a".."z")'

Remember that the range operator .. produced a list of values. If you wish, you may print them comma separated by setting the $, special variable:

perl -le '$, = ","; print ("a".."z")'

There are many more special variables. Take a look at my special variable cheat sheet for a complete listing.

Syntactically more appealing is to use join to separate the list with a comma:

perl -le 'print join ",", ("a".."z")'

Here the list a..z gets joined by a comma before printing.

50. Generate and print all the strings from "a" to "zz".

perl -le 'print ("a".."zz")'

Here the range operator .. is used again. This time it does not stop at "z" as in the previous one-liner, but advances z by one-character producing "aa", then it keeps going, producing "ab", "ac", ..., until it hits "az". At this point it advances the string to "ba", continues with "bb", "bc", ..., until it reaches "zz".

Similarly, you may generate all strings from "aa" to "zz" by:

perl -le 'print "aa".."zz"'

Here it goes like "aa", "ab", ..., "az", "ba", "bb", ..., "bz", "ca", ... "zz".

51. Create a hex lookup table.

@hex = (0..9, "a".."f")

Here the array @hex gets filled with values 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 and letters a, b, c, d, e, f.

You may use this array to convert a number (in variable $num) from decimal to hex using base conversion formula:

perl -le '$num = 255; @hex = (0..9, "a".."f"); while ($num) { $s = $hex[($num%16)&15].$s; $num = int $num/16 } print $s'

Surely, much easier way to convert a number to hex is just using the printf function (or sprintf function) with %x format specifier. (The example above just illustrates a use of a hex lookup table that we created by using the range operator.)

perl -le '$hex = sprintf("%x", 255); print $hex'

(See my Perl printf and sprintf format cheat sheet for all the format specifiers.)

To convert the number back from hex to dec use the hex function:

perl -le '$num = "ff"; print hex $num'

The hex function takes a hex string (beginning with or without "0x") and converts it to decimal.

52. Generate a random 8 character password.

perl -le 'print map { ("a".."z")[rand 26] } 1..8'

Here the map function executes ("a".."z")[rand 26] code 8 times (because it iterates over the dummy range 1..8). In each iteration the code chooses a random letter from the alphabet. When map is done iterating, it returns the generated list of characters and print function prints it out by concatenating all the characters together.

If you also wish to include numbers in the password, add 0..9 to the list of characters to choose from and change 26 to 36 as there are 36 different characters to choose from:

perl -le 'print map { ("a".."z", 0..9)[rand 36] } 1..8'

If you need a longer password, change 1..8 to 1..20 to generate a 20 character long password.

53. Create a string of specific length.

perl -le 'print "a"x50'

Operator x is the repetition operator. This one-liner creates a string of 50 letters "a" and prints it.

If the repetition operator is used in list context, it creates a list (instead of scalar) with the given elements repeated:

perl -le '@list = (1,2)x20; print "@list"'

This one liner creates a list of twenty repetitions of (1, 2) (it looks like (1, 2, 1, 2, 1, 2, ...)).

54. Create an array from a string.

@months = split ' ', "Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec"

Here the @months gets filled with values from the string containing month names. As each month name is separated by a space, the split function splits them and puts them in @months. This way $months[0] contains "Jan", $months[1] contains "Feb", ..., and $months[11] contains "Dec".

Another way to do the same is by using qw// operator:

@months = qw/Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec/

The qw// operator takes a space separated string and creates an array with each word being an array element.

55. Create a string from an array.

@stuff = ("hello", 0..9, "world"); $string = join '-', @stuff

Here the values in array @stuff get turned in a string $string that has them separated by a hyphen. Turning an array in a string was done by the join function that takes a separator and a list, and concatenates the items in the list in a single string, separated by the separator.

56. Find the numeric values for characters in the string.

perl -le 'print join ", ", map { ord } split //, "hello world"'

This one-liner takes the string "hello world", splits it into a list of characters by split //, "hello world", then it maps the ord function onto each of the characters, which returns the numeric, native 8-bit encoding (like ASCII or EBCDIC) of the character. Finally all the numeric values get joined together by a comma and get printed out.

Another way to do the same is use the unpack function and specify C* as the unpacking template (C means unsigned character and * means as many characters there are):

perl -le 'print join ", ", unpack("C*", "hello world")'

57. Convert a list of numeric ASCII values into a string.

perl -le '@ascii = (99, 111, 100, 105, 110, 103); print pack("C*", @ascii)'

Just as we unpacked a string into a list of values with the C* template in the one-liner above, we can pack them back into a string.

Another way to do the same is use the chr function that takes the code point value and returns the corresponding character:

perl -le '@ascii = (99, 111, 100, 105, 110, 103); print map { chr } @ascii'

Similar to one-liner #55 above, function chr gets mapped onto each value in the @ascii producing the characters.

58. Generate an array with odd numbers from 1 to 100.

perl -le '@odd = grep {$_ % 2 == 1} 1..100; print "@odd"'

This one-liner generates an array of odd numbers from 1 to 99 (as 1, 3, 5, 7, 9, 11, ..., 99). It uses the grep function that evaluates the given code $_ % 2 == 1 for each element in the given list 1..100 and returns only the elements that had the code evaluate to true. In this case the code tests if the reminder of the number is 1. If it is, the number is odd and it has to be put in the @odd array.

Another way to write is by remembering that odd numbers have the low-bit set and testing this fact:

perl -le '@odd = grep { $_ & 1 } 1..100; print "@odd"'

Expression $_ & 1 isolates the low-bit, and grep selects only the numbers with low-bit set (odd numbers).

See my explanation of bit-hacks for full explanation and other related bit-hacks.

59. Generate an array with even numbers from 1 to 100.

perl -le '@even = grep {$_ % 2 == 0} 1..100; print "@even"'

This is almost the same as the previous one-liner, except the condition grep tests for is "is the number even (reminder dividing by 2 is zero)?"

60. Find the length of the string.

perl -le 'print length "one-liners are great"'

Just for completeness, the length subroutine finds the length of the string.

61. Find the number of elements in an array.

perl -le '@array = ("a".."z"); print scalar @array'

Evaluating an array in a scalar context returns the number of elements in it.

Another way to do the same is by adding one to the last index of the array:

perl -le '@array = ("a".."z"); print $#array + 1'

Here $#array returns the last index in array @array. Since it's a number one less than the number of elements, we add 1 to the result to find the total number of elements in the array.

Perl one-liners explained e-book

I've now written the "Perl One-Liners Explained" e-book based on this article series. I went through all the one-liners, improved explanations, fixed mistakes and typos, added a bunch of new one-liners, added an introduction to Perl one-liners and a new chapter on Perl's special variables. Please take a look:

Have Fun!

Have fun with these one-liners for now. The next part is going to be about text conversion and substitution.

Can you think of other string creating and array creation one-liners that I didn't include here?

This article is part of the article series "Perl One-Liners Explained."
<- previous article next article ->

Comments

Anonymouse Cow-art Permalink
January 07, 2010, 21:46

Some things I'd do differently:

perl -E 'say ...' instead of perl -le 'print ...'

54. Create an array from a string:

@a = qw( words to end up in the array );

Roman Permalink
January 07, 2010, 22:07

ASCII is not an 8-bit encoding. 8=]

January 08, 2010, 01:48

Anonymouse Cow-art, thanks for the suggestions, I added the one on using qw() to the article! Talking about perl -E 'say ...', I don't want to use it yet, because 99% of the systems are still on Perl <= 5.8.

January 08, 2010, 01:48

Roman, theoretically speaking. :)

bse Permalink
January 08, 2010, 09:40

Thanks, I had almost forgotten why i don't like perl. you reminded me.

January 08, 2010, 11:18

Another string manipulation, easy to remember: reverse

$ perl -le '$_=q{dlrow olleh}; print scalar reverse;'
hello world

/usr/bin/tac does it by lines, like 'cat' but reversing the file. Perl reverse() can work with scalar, list (the default) and hash variables.

January 08, 2010, 12:34

>perl -le 'print map { ("a".."z")[rand 26] } 1..8'

>Here the map function executes ("a".."z")[rand >26] code 8 times (because it iterates over the >dummy range 1..8).
OK.
>In each iteration the code >chooses a random >letter from the alphabet.
Would you please explain how that works?

January 08, 2010, 15:21

poisonbit, thanks for the one-liner! This will go into the next part on text conversion and manipulation.

Btw, there is also Unix utility `rev` that does line reversing!

January 08, 2010, 15:27

q, really easy, the ("a".."z") part creates a list of all letters from a to z. You can think of it as putting all letters in an array:

perl -le '@letters = ("a".."z")'

Next, this array can be indexed to choose individual letters from it. There are 26 letters in the alphabet so $letters[0] is "a" and $letters[1] is "b", ..., $letters[25] is "z".

Now what I do is I use rand function to choose some letter at random:

perl -le '@letters = ("a".."z"); print $letters[rand 26]'

But you can skip the @letters array and just use ("a".."z") in its place:

perl -le 'print (("a".."z")[rand 26])'

And I need to do this several times, so I create a loop that executes 8 times by using map function on a range 1..8,

perl -le 'print map { ("a".."z")[rand 26] } 1..8'

That's it.

kangu Permalink
January 08, 2010, 15:28

Awesome post keep goin on buddy we are really learning interesting stuffs here.

January 08, 2010, 16:07

But you can skip the @letters array and just use (”a”..”z”) in its place
perl -le 'print (("a".."z")[rand 26])'

Ok, understood. Thank you. Where can I read that in the documentation?

January 08, 2010, 16:23

q, read up on array slices on perldoc.

Raffaello Permalink
February 05, 2010, 13:33

Great article! Learned a lot!

Raffaello Permalink
February 05, 2010, 18:50

I see redundancy in 58:

perl -le '@odd = grep {$_ % 2 == 1} 1..10; print "@odd"'

is equivalent to

perl -le '@odd = grep { $_ % 2 } 1..10; print "@odd"'

February 06, 2010, 13:43

Raffaello, that's right. Any of them are good.

deindorfer Permalink
June 11, 2010, 17:07

58, shorter still:

perl -le 'print grep { $_ % 2 } 1..10'

senthilvinayagam Permalink
July 07, 2011, 13:53

great utility. i was very useful for me.

Hawk Permalink
August 17, 2011, 15:07

Easier to read:

perl -le "map{print if$_%2}1..10"

Carl Winbäck Permalink
November 29, 2011, 11:03

This is a very neat resource, thank you!

saravanan Permalink
May 29, 2012, 15:34

hi friends,

I have doubt in array
[01, 03, 05, 07, 09, 10]
[02, 04, 06, 07, 08, 10]

If more than two even number in my array, print;

so i have to print only [02, 04, 06, 07, 08, 10]

How do this? please clarify me

Leave a new comment

(why do I need your e-mail?)

(Your twitter name, if you have one. (I'm @pkrumins, btw.))

Type the word "cloud_190": (just to make sure you're a human)

Please preview the comment before submitting to make sure it's OK.

Advertisements