## š Separating groups of digits using Perl 6

Put commas between the three-digit groups in a big number.

The task is to print an integer number, for example, 1234567890,in the form of 1,234,567,890.

Here is a possible solution that uses a lot of Perl 6 facilities:

`\$n ~~ s/<?after \d> (\d ** 3)+ \$/{\$0.map(',' ~ *).join}/;`

On the top level, weāve got a substitutionĀ `s///`. The pattern is anchored to the end of the string:Ā `s/...\$//`. From the end of the string, groups of three digits are searched:Ā `(\d ** 3)+`. A singleĀ `\d` matches a digit, and theĀ `**` quantifier requires exactly three of them. The second quantifier,Ā `+`, allows more than one such groups.

A dot may only follow at least one digit. To avoid converting six-digit numbers to something likeĀ .123.456, a look-behind assertionĀ `<?after \d>` is inserted, which insists that there is a digit before the first group of three digits.Ā The whole replacement only happens if there are more than four digits in the original number.

The second part of the substitution is an executable code:Ā `s//{...}/`. After a successful match, the three-digit groups appear in the match objectĀ `\$0`. Because of theĀ `+` quantifier, you can treat this object as an array.

First, each element is translated to a string with a comma in front of it:Ā `map(',' ~ *)`. Using theĀ `*` character creates a `WhateverCode` block, which is equivalent toĀ `{',' ~ \$_}`. It is also possible to rewrite the map operation using the string interpolation:Ā `map({",\$_"})`.

Finally, transformed parts are joined together, using theĀ `join` method call. TheĀ `\$n` variable now contains a string with the desired result.

## š Separating digits and letters using Perl 6

In a given string that contains letters and digits, insert dashes on the borders between the digit and letter sequences.

The goal of the task is to convert, for example, the stringĀ 6TGT68 toĀ 6-TGT-68. With some modification, this task may be needed for creating the canonical form of car license plates in some countries.

There are character classes in the Perl 6 regexes:Ā `<:alpha>` for alphabetical characters andĀ `<:digit>` for digits. Let us use them for finding the borders between digits and letters. In other words, we need to find all the sequences of two characters, where one of them is a letter and another is a digit.

`my \$s = '6TGT68';\$s ~~ s:g/    (<:alpha>) (<:digit>) |    (<:digit>) (<:alpha>)   /\$0-\$1/;say \$s; # 6-TGT-68`

The replacement constructĀ `s:g///` is applied globally. It finds all the places, which match eitherĀ `<:alpha> <:digit>` orĀ `<:digit><:alpha>`.

When the match is found, theĀ `\$0` andĀ `\$1` variables are set to either a letter and a digit or to a digit and a letter. The parentheses indices count from zero in each alternative separated with a vertical bar.

The replacement uses the found characters and inserts a hyphen character between them. Notice that the spaces in the regex are allowed and ignored, while the spaces in the replacement part are significant, so theĀ `/\$0-\$1/` part should not contain additional spaces.

## š Removing duplicated words using Perl 6

Remove repeated words fromĀ froma sentence.

Repeated words are most often unintended typing mistakes. In rare cases, though, this is correct like with the word that:

He said that that tree is bigger

Anyway, let us remove the double words ignoring the grammar for now. To find if the word is repeated, a regex with variables can be used. Then, using a substitution, only one copy of a word is passed to the resulting string.

`my \$string = 'This is is a string';\$string ~~ s:g/ << (\w+) >> ' ' << \$0 >> /\$0/;say \$string;`

The regex part of theĀ sroutine is a regex that is first looking for a word (as a sequence of word charactersĀ `\w+`) and its copy after a space. The first occurrence is saved in theĀ `\$0` variable, which is immediately used in the same regex. It is also used in the replacement part.

To prevent repetitions, the word-edge anchors are used:Ā `<<` for the beginning of a word andĀ `>>` for its end. In the given example, this prevents treating the last two letters of the wordĀ This as a separate word,Ā is, and thus, the correct phraseĀ This is a string will not be broken after the substitution.

Notice that non-literal spaces in a regex are not taking part in string matching, although, they are necessary in a sequenceĀ `<< (\w+) >>`. The constructionĀ `<<(\w+)>>` is a syntax error as it is similar to the character classĀ `<[...]>` or a reference to a named regex likeĀ `<:alnum>`, and the compiler prefers explicit spaces in this case.

## š Doubling characters using Perl 6

In a given string, double each alphanumeric character and print the result. Punctuation and spaces should stay untouched.

Regexes are very powerful tools for searching and replacing texts. In this task, only the alphanumeric characters are requested to be doubled. TheĀ `\w` character class is the perfect match to find these characters.

`my \$string = 'Hello, 1 World!';\$string ~~ s:g/(\w)/\$0\$0/;say \$string;`

We are using theĀ `s///` construct here. TheĀ `\$string` is matched against theĀ `\w` regex. The parentheses aroundĀ `\w` capture the found character. It is now contained in theĀ `\$0` special variable.

In the second part of the replacement,Ā `\$0` is used twice, and, thus, the doubled character is replacing the single character found in the string. TheĀ `:g` adverb makes the replacement global.

The program prints the following output:

`HHeelllloo, 11 WWoorrlldd!`

Let us update the program to exclude theĀ `r` letter from the process. In other words, all the characters, exceptĀ `r`, must be doubled. Build a new character class as a difference betweenĀ `\w` andĀ `r` as demonstrated in the following line of code:

`\$string ~~ s:g/(<[\w] - [r]>)/\$0\$0/;`

Now, the output is a bit different:

`HHeelllloo,Ā 11Ā WWoorldd!`

## š Currency converter written in Perl 6

Parse the string with a currency converting request such as ā10 EUR in USDā and print the result.

The task of understanding free text is quite complicated. For the currency conversion, we can create a simple regex that matches the most common quires.

Letās ignore the way the exchange rate data are obtained and use the hard-coded values:

`my %EUR =    AUD => 1.4994,  CAD => 1.4741,    CHF => 1.1504,  CNY => 7.7846,    DKK => 7.4439,  GBP => 0.89148,    ILS => 4.1274,  JPY => 131.94,    RUB => 67.471,  USD => 1.1759;`

This hash contains the exchange rates of a few currencies to Euro. Thus, it is possible to directly use it to get the results for any pair with EUR, such as:

`10 EUR in GBP20 ILS toEUR`

For other combinations, a cross-rate can be used. For example, the request to convert JPY to CHF uses the values of JPY-to-EUR and EUR-to-CHF conversion.

Here is a regex that parses the textual request:

`\$request ~~     /(<[\d .]>+) \s* (<:alpha> ** 3) .* (<:alpha> ** 3)/;`

Letās also make a loop to accept multiple requests from the keyboard.

Here is the program:

`while (my \$request = prompt('> ')) {    \$request ~~         /(<[\d .]>+) \s* (<:alpha> ** 3) .* (<:alpha> ** 3)/;    my (\$amount, \$from, \$to) = \$0, \$1, \$2;        my \$result = 0;    if \$to eq 'EUR' {       \$result = \$amount / %EUR{\$from};    }    elsif \$from eq 'EUR' {       \$result = \$amount * %EUR{\$to};    }    else {       \$result = \$amount * %EUR{\$to} / %EUR{\$from};    }    say "\$amount \$from = \$result \$to";}`

After the regex match, the values are copied to the three variables:Ā `\$amount`,Ā `\$from`, andĀ `\$to`. TheĀ `if`ā`elsif`ā`else` chain is used to choose how the new amount is calculated: either as direct or cross rate.

Run the program and enter different requests with both integer and floating-point values for different combinations of the currency codes listed in theĀ `%EUR` hash.

Here are a few ideas of how to improve the program:

1. Check if the entered currency code exists.
2. Make the request case-insensitive.
3. Create another hash with exchange rates against USD and choose it, whenever possible, to avoid cross-calculations.

## š Skipping Pod documentation in Perl 6

Create the program that copies the input text and skips the documentation in the Pod style that starts withĀ `=begin` and ends withĀ `=end`.

Let us take a simple text containing a piece of Pod documentation:

`# Hello, World!=beginThis program prints a message=endsay 'Hello, World!';`

The program should read it and print everything that is not the comment. Thus, for the given example, only the first and the last lines can go to the output.

In Perl 6, there is a family ofĀ flipflop operators that, although being a bit hard to understand at first, are quite powerful for introducing the two-state triggers in the program flow.

`while \$_ = \$*IN.get {    .say unless /^'=begin'/ ff /^'=end'/;}`

Reading lines from the STDIN handle is the same as it will be done it in task 95,Ā TheĀ catutility. The flipflop constructĀ `/^'=begin'/ ff /^'=end'/` isĀ `False` initially and becomesĀ `True` as soon as theĀ `\$_` content matches the first regex. After that, it staysĀ `True` until the second condition isĀ `True`. In the end, theĀ `unless` clause only passes the lines that are not located between theĀ `=begin` andĀ `=end` instructions. TheĀ `.say` method call is thus printing all the remaining lines.

## š Count words using Perl 6

Count the number of words in a text.

Before solving the task, let us assume that by words we mean here a sequence of alphanumeric characters, including the underscore symbol.

Here is the solution:

`my \$text = prompt('Text> ');say \$text.comb(/\w+/).elems;`

Try it on a few test inputs:

`\$perl6 countwords.pl Text> Hello, World;2`

The program uses regexes for extracting words using theĀ `\w` character class and theĀ combstring method that returns a sequence of the words:

`\$text.comb(/\w+/)`

TheĀ `+` quantifier allows a repetition ofĀ `\w`, so it matches the whole word.Ā

Alternatively, a more traditional match with a regex may be used:

`\$text ~~ m:g/(\w+)/;say \$/.elems;`

Parentheses in the regex capture the word, and theĀ `:g` adverb applies it a few times until all the words are found. TheĀ `\$/` variable (called theĀ match object) keeps all the matched substrings, and theĀ `elems` method returns the number of elements in it.