Split Regex, return only characters, digits and underscores. Perl

Viewed 162

Attempting to break up the line

#!/usr/bin/perl -w

with the following code

use strict;
use warnings;

my %words;

while (my $line = <>)
{
foreach my $word (split /:|,\s*|\/|!|\#|-/, $line)
{
    $words{$word}++;
}
}

foreach my $word (keys %words)
{
print "$word: $words{$word}\n";
}

Is there an easier way to have the split command only split at words, numbers and underscores? Rather than setting all of these delimiters.

Attempting to get the output

usr: 1
bin: 1
perl: 1
2 Answers

Don't split, extract.

++$words{$_} for $line =~ /\w+/g;

You can also do this with split and the negated word character class:

foreach my $word (split /\W+/, $line) {
  $words{$word}++;
}

But note that since your string starts with non-word characters, the first word it will return is the empty string at the beginning of the string.

Another tool for this task (but more suited to prose than code and filenames) is the unicode word boundary, which uses Unicode rules for where words start and end, and takes into account things like apostrophes being part of words (can't). To utilize this, you'd first need to split your input into a list containing both words and non-words, and then find the words (easiest way is probably to use any elements that contain at least one word character):

foreach my $word (grep { m/\w/ } split /\b{wb}/, $line) {
  $words{$word}++;
}

The \b{wb} regex sequence requires Perl 5.24+.

Related