views:

587

answers:

5

I'm trying to find a way to place a colon ( : ) into a string, two characters from the end of the string.

Examples of $meetdays:
1200 => 12:00
900 => 9:00
1340 =>13:40

Not sure if this should be a regular expression or just another function that I'm not aware of.

+1  A: 

You could try this:

s/..$/:$&/

it matches two-characters at the end of the string, and replaces it with a colon, and the matched string (i.e. the two characters).

EDIT
Fixed sed-backref to the perl equivalent.

roe
ok thanks... yeah i was going to say that it wasnt working
CheeseConQueso
nice.. there it is
CheeseConQueso
Ok, so it isn't the most optimized expression, but it's easy to understand and does the trick, how was that unhelpful (as in downvote)? Isn't upvoting the better answer the SO way?
roe
innaM
Seriously, have you people not heard of solve first, optimize later IF there's a performance problem? I already admitted it's not the most optimized (will you stop beating it into the ground already?), but it does the trick, and it's easy to grasp.
roe
Please don't attack a perfectly valid solution, promote the better one instead.
roe
roe: the perl documentation says not to use it *ever* because *all* regex in *all* included files take a *significant* performance hit. Seeing regex is used everywhere, i think its fair to *not* make it slower *everywhere* at once, when there is an easier way to solve the problem without the penalty
Kent Fredric
roe
roe
CheeseConQueso
The same reason why you should always use a sledgehammer when driving in nails; there exists cases where the regular hammer is insufficient.
roe
+8  A: 
s/(?=..$)/:/

Don't use roe's suggestion of $&. perldoc perlvar:

The use of this variable anywhere in a program imposes a considerable performance penalty on all regular expression matches. See "BUGS".

ayrnieu
As always, there are more than one way. There's a performance penalty yes, but it was the first pattern that came to mind (yes, I'm a sed guy originially of course), and it's probably fast enough in this case, don't you think? :)
roe
it was fast enough.. its a really small script anyway... ayrnieu's solution worked too
CheeseConQueso
innaM
Why use the fancy "zero-width positive lookahead" operator (?=) when an ordinary s/(..)$/:$1/ would work fine, including in older versions of Perl (and even in many non-Perl regex implementations) where ?= doesn't work?
j_random_hacker
I expect pain from non-Perl regex implementations; I don't hurt myself in anticipation of them. You'll have to go back farther than ten years to find a perl that doesn't support zero-width lookaheads.
ayrnieu
Fair enough. I didn't realise zero-width lookaheads were introduced in Perl 5 -- I assumed they were more recent than that.
j_random_hacker
Since this question somehow got to be a matter of slow vs fast code: s/(?=..$)/:/ is 26 times slower than s/(..)$/$1/ with perl 5.10 and 13 times slower with perl 5.8
innaM
@Manni: Interesting. I know that Perl optimises some common cases in regexes, e.g. those ending in "$" -- maybe that optimisation is not done for lookahead expressions. In that case I imagine it will eventually be addressed by the Perl core developers.
j_random_hacker
You really can't claim relative speediness. It depends on various things like the compiler that built perl, the various options, etc. You can get away with saying it's slower, but your relative results are only valid for your own configuration.
brian d foy
A: 

The Perl equivalent of sed's & is $&, so it should be:

 $s = s /..$/:$&/s;
Zsolt Botykai
A: 

roe's answer "works" , but its rather inobvious regex.

I would more go for

s/(^.*)(..$)/$1:$2/

Because I just love backrefs.

Its overkill for what you're doing, but to me its more semantically expressive.

Kent Fredric
the first capture is a bit wasted, why not simply s/(..$)/:$1/ ?
Although the first part is really redundant, it is a lot more readable. ( At least to the way I parse regex )
Kent Fredric
+1 blixtor. @Kent: although it makes no practical difference in this case, your original answer is slower since Perl will need to backtrack two characters to match the final "..". If that ".." was a more complicated expression, the initial ".*" could easily make it *much* slower.
j_random_hacker
+9  A: 

Can also use substr() as well.....

my $string = "1200";
substr $string, -2, 0, ':';

# $string => '12:00';

/I3az/

draegtun
I would imagine the substr() is significantly faster as well as easier to read and more intuitive.
Joe Casadonte
More intuitive only if you don't know regexes well enough.
PEZ
this one looks intuitive... dont know why, but it created 20~ lines in the csv file and then took a dump and gave me this error... substr outside of string at ./test3 line 237. - my best guess is that it ran into a value of 0, which happens in my data and is not bad data, just implies a diff event
CheeseConQueso
"substr outside of string" error means that you have data in your CSV that is less than 2 characters wide. Thus it cannot insert the ':' two chars (-2) from the end. If u have "diff event" then you need to filter use of the substr or regex accordingly.
draegtun