in reply to Recognizing 3 and 4 digit number

Just use negative look-arounds to ensure that you do not have a digit on either side of a 3 or 4 digit number:

my @strings = ( 'foo1234bar', '1234 5678', 'abcd9012f123ab', '123', ' 123', '123 ', ); foreach my $string (@strings) { my(@nums) = $string =~ m/(?<!\d)(\d{3,4})(?!\d)/g; local $" = ','; print "<$string>: (@nums)\n"; }

The output:

<foo1234bar>: (1234) <1234 5678>: (1234,5678) <abcd9012f123ab>: (9012,123) <123>: (123) < 123>: (123) <123 >: (123)

An advantage of using negative lookarounds is that you don't have to explicitly accommodate conditions such as the start or end of string or line. The negative lookarounds are just saying "a digit cannot come immediately before or after a sequence of 3 or 4 digits". With positive lookarounds you would have to say "either a non-digit or end of string must come before and after a sequence of 3 or 4 digits." That would look something like this (untested):

m/(?<^|\D)(\d{3,4})(?=$|\D)/mg

So rather than asserting what must come before and after the digits, the regexp becomes simpler if we just assert what cannot come before or after.


Dave

Replies are listed 'Best First'.
Re^2: Recognizing 3 and 4 digit number
by kcott (Archbishop) on Jan 03, 2017 at 04:46 UTC

    G'day Dave,

    At first glance, I thought your regex was better than mine and so I decided to try it. I plugged it into my code but it failed on the phone number and date tests (details in spoiler). The OP requirements are not the best but excluding phone numbers and dates seems to be definitely wanted.

    — Ken

      Wah! I guess I got excited and answered before noticing that we wanted to disqualify things that look like phone numbers. Sorry.

      This isn't tested:

      m/(?<![\d-])(\d{3,4})(?![\d-])/

      But it would run afoul of phone numbers using commas to separate, or wrapping parens around area codes.

      It might be useful to take a first pass and keep a list of offsets for "numbers" that should be ignored. It's probably easier to match a phone number with existing libraries than to match a 3 or 4 digit number that is not part of a phone number. In other words, on first pass, identify phone numbers, IP addresses, and other problematic numbers, and push their offsets and lengths into an array. Then on second pass disqualify any number that falls within one of the offset/length sets.


      Dave