Question

In Perl, I'm looking to split a string before the first letter (regardless of its position). I don't want the delimiter to disappear.

For example, if the string was 12345AB2345 I want to split on the first letter A I want two strings: 12345 and AB2345.

I tried using code like the following, but it does it does not split correctly.

$string = "12345A2345"
$substring = substr($string, 0, index($string, /[a-zA-Z]/);
$remainder = substr($string, index($string, /[a-zA-Z]/);

There can be more than one letter in the string.

I think my problem deals with the fact that substr cannot use regular expressions.

Was it helpful?

Solution 2

I would probably use split here, since that's what you're doing after all. Below I give you the choice between 3 ways:

#!/usr/bin/perl

use strict;
use warnings;

use Test::More;

while( <DATA>)
  { chomp;
    my( $string, $expected_substring, $expected_remainder)= split /\s+/;

    { # method 1: split on letter, captured letter is added to the remainder
      #           the 3rd arg to split is the LIMIT (see perldoc -f split)
      my( $substring, $letter, $remainder)= split /([a-zA-Z])/, $string, 2;
      $remainder= $letter . $remainder if $letter;

      is( $substring, $expected_substring, "method 1, substring, s: '$string'");
      is( $remainder, $expected_remainder, "method 1, remainder, s: '$string'");
    }

    { # method 2: add space before letter, split on space 
      my $string_copy= $string;          # or $string would be modified
      $string_copy=~ s/([a-zA-Z])/ $1/;
      my( $substring, $remainder)= split / /, $string_copy, 2;

      is( $substring, $expected_substring, "method 2, substring, s: '$string'");
      is( $remainder, $expected_remainder, "method 2, remainder, s: '$string'");
    }

    { # method 3: method 2 shortened using s//r (perl 5.14 and above)
      my( $substring, $remainder)= split / /,  $string=~ s/([a-zA-Z])/ $1/r, 2;

      is( $substring, $expected_substring, "method 3, substring, s: '$string'");
      is( $remainder, $expected_remainder, "method 3, remainder, s: '$string'");
    }
  }

done_testing();

# test data, string, substring and remainder are on one line, space separated
__DATA__
12345A678  12345 A678  
12345AB678 12345 AB678
12345A67B8 12345 A67B8
12345678   12345678

OTHER TIPS

And yet another way:

my $string = "12345A2345";
my ($substring, $remainder) = split /(?=[a-z])/i, $string, 2;

Try,

my ($substring,$remainder) = $string =~ /^([^a-zA-Z]*)([a-zA-Z].*)$/ ;

If you need to handle the case where there are no letters, then you could do:

my ($substring,$remainder) = $string =~ /^([^a-zA-Z]*)([a-zA-Z].*)?$/ ;
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top