How can I get the CENTER n chars from a string?

M

Mr P

Lets say I want the CENTER 2 characters from any (even length) string?

123456 .. 34
ABC123 .. C1
1223 ..22
1234567890 .. 56
AB .. AB


is there A regex that can handle this for ANY even length string? Im
pretty good with regexes but I cant think of one that can handle it.

sorta like
s/(.+)(..)(.+)/$2/ where the length of $1 == length of $2..

Thanks!
 
J

Jozxyqk

Mr P said:
Lets say I want the CENTER 2 characters from any (even length) string?
is there A regex that can handle this for ANY even length string? Im
pretty good with regexes but I cant think of one that can handle it.

Why use a regex?

substr($string,length($string)/2-1,2);
 
M

Mr P

Well, the obvious way would be

    /(.+)(..)(??{ "." x length $1 })/

In principle it ought to be possible to do this by treating it as a
bracketed construct, using the new recursion primitives in 5.10, but
while

    /^( . (?: (..) | (?1) ) . )$/x

performs the match correctly, the recursion resets $2 so you lose the
capture. This can be fixed with

    use vars qw/$centre/;
    /^( . (?: (..)(?{ $centre = $2 }) | (?1) ) . )$/x

but IIRC referencing lexicals is one of the things you mustn't do from
within a (?{}) group (there are nasty bugs here) so you have to use a
package global instead.

Ben

Ahh very helpful Ben thanks!
 
M

Mr P

Why use a regex?

substr($string,length($string)/2-1,2);

I'd thought of this approach and even played with it a bit- you left
out the test for *evenness* however. I just love regexes I'd hoped
there was something simple Id missed like some assertion that would
make it EZ.. Ben's solution is pretty durn good though!
 
D

Dr.Ruud

Mr said:
I'd thought of this approach and even played with it a bit- you left
out the test for *evenness* however. I just love regexes I'd hoped
there was something simple Id missed like some assertion that would
make it EZ.. Ben's solution is pretty durn good though!

Question 1 was: Why use a regex?
Question 2 is: Why did you lie about the string having an even length?

And as a direction, you presented a substitution in stead of a regex.

perl -wle '
my $center = @ARGV ? $ARGV[0] : q{TE$T};
exit 1 if $center =~ /\A(?:..)*.\z/s; # odd

1 while $center =~ s/\A.(.{2,}).\z/$1/s;

print $center;
'
E$
 
J

Justin C

Lets say I want the CENTER 2 characters from any (even length) string?

123456 .. 34
ABC123 .. C1
1223 ..22
1234567890 .. 56
AB .. AB


is there A regex that can handle this for ANY even length string? Im
pretty good with regexes but I cant think of one that can handle it.

sorta like
s/(.+)(..)(.+)/$2/ where the length of $1 == length of $2..

Don't use a regex, use substr() and some maths.

Something like: my $str = substr($_, (length($_)/2) - 1, 2);

I see that you are asking for a regex, and while I don't think that's
the appropriate way to do it, it is possible that you're asking for a
regex to do this for a reason. If you really want a regex then that's
beyond my current regex ability.... actually:

my $c = length($_);
$_ =~ s/^.{$c}(.{2}).{$c}/$1/;

Thank you for the little puzzle which has aided my education!

Justin.
 
J

Justin C

Lets say I want the CENTER 2 characters from any (even length) string?

123456 .. 34
ABC123 .. C1
1223 ..22
1234567890 .. 56
AB .. AB


is there A regex that can handle this for ANY even length string? Im
pretty good with regexes but I cant think of one that can handle it.

sorta like
s/(.+)(..)(.+)/$2/ where the length of $1 == length of $2..

Thanks!

I know my last post was wrong! I'm just posting before everyone jumps on
it! What I meant was:

my $c = (length($_) / 2) - 1;
$_ =~ s/^.{$c}(.{2}).{$c}$/$1/;

Justin.
 
D

Dr.Ruud

Justin said:
my $c = (length($_) / 2) - 1;
$_ =~ s/^.{$c}(.{2}).{$c}$/$1/;

You can get into trouble there with embedded newlines.

You can change it to

( $_ ) = /^ .{$c} (..) /sx;

Or even better, to

$_ = substr( $_, length() / 2 - 1, 2 );
 
M

Mr P

Just to see what error it would throw- I tried this:

s/^(.*)(..)(.*)$/$2/ if length $1 == length $2;

Curiously it said *attempted to modified a read-only value* which I
thought was odd- I don't see where I'm trying to do that at all. I
expected it to say something was un-innited or something like that?
 
M

Mr P

I'd thought of this approach and even played with it a bit- you left
out the test for *evenness* however. I just love regexes I'd hoped
there was something simple Id missed like some assertion that would
make it EZ.. Ben's solution is pretty durn good though!

Question 1 was: Why use a regex?
Question 2 is: Why did you lie about the string having an even length?

And as a direction, you presented a substitution in stead of a regex.

perl -wle '
     my $center = @ARGV ? $ARGV[0] : q{TE$T};
     exit 1 if $center =~ /\A(?:..)*.\z/s;  # odd

     1 while $center =~ s/\A.(.{2,}).\z/$1/s;

     print $center;
'
E$

OMG dude!
 
U

Uri Guttman

P> Just to see what error it would throw- I tried this:
P> s/^(.*)(..)(.*)$/$2/ if length $1 == length $2;

P> Curiously it said *attempted to modified a read-only value* which I
P> thought was odd- I don't see where I'm trying to do that at all. I
P> expected it to say something was un-innited or something like that?

regardless of that error, that will never work. the if modifier is
executed BEFORE the s///. that means it looks at the previous settings
of $1 and $2 from some other regex.

uri
 
C

C.DeRykus

You can get into trouble there with embedded newlines.

You can change it to

   ( $_ ) = /^ .{$c} (..) /sx;

or, even prime it with pos(), although
maybe there'd be no speedup.

pos() = $c;
($_) = /(..)/g;
Or even better, to

   $_ = substr( $_, length() / 2 - 1, 2 );

Agree totally - this'd be fastest.
 
H

Hecht

Lets say I want the CENTER 2 characters from any (even length) string?

123456 .. 34
ABC123 .. C1
1223 ..22
1234567890 .. 56
AB .. AB


is there A regex that can handle this for ANY even length string? Im
pretty good with regexes but I cant think of one that can handle it.

sorta like
s/(.+)(..)(.+)/$2/ where the length of $1 == length of $2..

Thanks!
I would do this in this way:


my $string = "123456";
my @string = split //, $string;
my $length = @string;
my $result= $length/2;
print $string[$result-1] . $string[$result];

crude but works.

Daniel
 
W

Willem

Hecht wrote:
) I would do this in this way:
)
)
) my $string = "123456";
) my @string = split //, $string;
) my $length = @string;
) my $result= $length/2;
) print $string[$result-1] . $string[$result];
)
) crude but works.

Very crude indeed, given that the same can be achieved with simple
string operations, such as 'length' and 'substr', as already shown
crossthread. substr($string,length($string)/2-1,2) does the trick.


SaSW, Willem
--
Disclaimer: I am in no way responsible for any of the statements
made in the above text. For all I know I might be
drugged or something..
No I'm not paranoid. You all think I'm paranoid, don't you !
#EOT
 
J

Justin C

Lets say I want the CENTER 2 characters from any (even length) string?

123456 .. 34
ABC123 .. C1
1223 ..22
1234567890 .. 56
AB .. AB


is there A regex that can handle this for ANY even length string? Im
pretty good with regexes but I cant think of one that can handle it.

sorta like
s/(.+)(..)(.+)/$2/ where the length of $1 == length of $2..

Thanks!

I'm sure I posted a reply to this already, but it hasn't shown up here
after several days. So here it is again:

#!/usr/bin/perl

use warnings;
use strict;

while (<DATA>) {
chomp;
my $n = (length($_) / 2) - 1;
$_ =~ /^.{$n}(.{2}).{$n}$/;
print $1, "\n";
}

__DATA__
bear
wooden
coldbeer
golden cat
wobbly stool with three legs


Justin.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,184
Messages
2,570,976
Members
47,536
Latest member
MistyLough

Latest Threads

Top