Beefy Boxes and Bandwidth Generously Provided by pair Networks
Welcome to the Monastery
 
PerlMonks  

Re: Re: String Manupulation

by dragonchild (Archbishop)
on Aug 27, 2003 at 17:34 UTC ( #287104=note: print w/replies, xml ) Need Help??


in reply to Re: String Manupulation
in thread String Manupulation

Better is $string =~ tr/ /-/; Don't use substitution when transliteration is applicable.

------
We are the carpenters and bricklayers of the Information Age.

The idea is a little like C++ templates, except not quite so brain-meltingly complicated. -- TheDamian, Exegesis 6

Please remember that I'm crufty and crochety. All opinions are purely mine and all code is untested, unless otherwise specified.

Replies are listed 'Best First'.
Re^3: String Manupulation (yarn)
by tye (Sage) on Aug 27, 2003 at 21:09 UTC
    Better is $string =~ tr/ /-/; Don't use substitution when transliteration is applicable.

    Why? I often hear this advice and it usually stems from the fiction that "tr/// is always faster than s///".

    A better rule, IMHO, is to use the tool that fits best. In this case, both fit equally well. I personally prefer s/ /-/g because it will be recognized more widely.

    If I felt that the requirement was likely to become something like "change ' ' to '-' and tab to '_'", then I might start with tr/ /-/ in expectation of changing it to something like tr/ \t/-_/ (which could be done with s/// but not so cleanly). While if I felt that the requirement was likely to become something like "change whitespace to '-'", then I'd start with s/ /-/g in expectation of changing it to something like s/\s+/-/g (which could be done with tr/// but not so cleanly).

    In the very rare case where the performance difference between the two matters, which to use depends on your input. Benchmarking with one 10kB string I get:

    Rate 1tr 0tr 0s 1s 1tr 35435/s -- -1% -27% -30% 0tr 35863/s 1% -- -26% -29% 0s 48562/s 37% 35% -- -4% 1s 50833/s 43% 42% 5% --
    [ Note that "0s" and "1s" are identical as are "0tr" and "1tr". I usually include such so that runs of each case are interleaved so I get an idea how much variability there is between runs vs. real differences in performance. ]

    With a different 10kB string I get:

    Rate 0s 1s 0tr 1tr 0s 20623/s -- -2% -38% -38% 1s 20993/s 2% -- -37% -37% 0tr 33175/s 61% 58% -- -1% 1tr 33522/s 63% 60% 1% --
    Note that in both cases, the speed difference between s/// vs. tr/// is only a few micro seconds on a 10kB string so this is extremely unlikely to matter either way for the vast majority of uses.

                    - tye
      I personally prefer s/ /-/g because it will be recognized more widely.

      Perhaps it's worth using tr// just to correct that? :)

      My rationale has to do with the fact that, while the OP is substituting, the more correct statement is that the OP is transliterating. It has nothing to do with speed or the like. s/// is fast enough. tr/// better describes what's going on, given the information above. I agree that the correct tool for the anticipated requirements should be chosen. But, given the requirements as stated, I would argue that tr/// is correct. In fact, because tr/// is used less, I would argue that this is a benefit in the communication to the maintainer.

      ------
      We are the carpenters and bricklayers of the Information Age.

      The idea is a little like C++ templates, except not quite so brain-meltingly complicated. -- TheDamian, Exegesis 6

      Please remember that I'm crufty and crochety. All opinions are purely mine and all code is untested, unless otherwise specified.

Re: Re: Re: String Manupulation
by LeeC79 (Acolyte) on Aug 27, 2003 at 17:47 UTC
    Remember, I'm new. Be gentle. I'm simply trying to create a log file that will have the current date and timestamp as the filename. But I can't figure out what is wrong with my code. The only thing I can think of is that the filename I'm trying to use is to long.
    #!/usr/local/bin/perl -w use strict; my $localtime = scalar localtime; my $tmp = ".txt"; my $logfile = $localtime.$tmp; $logfile =~ tr/ /-/; open( OUTFILE, ">$logfile" ); print OUTFILE "Hello"; close(OUTFILE);
    And this is the error I get when trying to run:
    print() on closed filehandle OUTFILE at log.pl line 12.
    Any hints?
      Worked fine on my system. I'm running 5.6.0 on AIX. Now, a suggestion:
      open(OUTFILE, ">$logfile") || die "Cannot open '$logfile' for writing: + $!\n";

      That will tell you why it cannot open the file. (That's what the $! variable does.) You should always check the return value of open and similar functions.

      ------
      We are the carpenters and bricklayers of the Information Age.

      The idea is a little like C++ templates, except not quite so brain-meltingly complicated. -- TheDamian, Exegesis 6

      Please remember that I'm crufty and crochety. All opinions are purely mine and all code is untested, unless otherwise specified.

      The example 'ought to work', but if it doesn't, the problem is related to your open statement failing.

      It is always imperative to check the return value of open, to ensure that it succeeded. One common way is as follows:

      open ( OUTFILE, ">$logfile" ) or die "Can't open $logifle.\n$!";

      The other issue here is that if it turns out that it's failing, the probable reason is that logfile already exists and is either locked or set to permissions that prevent your script from opening it for writing.

      This leads to a couple of additional issues:

      First, you should probably either be testing for file pre-existance with:

      if (-e $filename) { do something } else {do something else}

      or opening for append rather than replace, with:

      open ( OUTFILE, ">>$logfile" ) or die "Can't open $logfile:\n$!";

      The other issue is that if the file is locked, it might just be a matter of waiting a second or two for it to be released by whoever is writing to it. ...which leads to another issue. If someone else (or some other program) is possibly writing to the same logfile, you really should be checking lock status prior to trying to open, and locking it when you use it, and appending to it rather than overwriting it.

      Just a few suggestions and things to consider.

      Dave

      "If I had my life to do over again, I'd be a plumber." -- Albert Einstein

      My guess is that open failed. It's never a good idea to assume that open succeeds.
      open( OUTFILE, ">$logfile") or die "Can't write to $logfile\n";
      Do you get the same error?
      it is probably a permissions problem. you don't have permission to create the logfile. to make sure this is the case try this:
      open (OUTFILE, ">$logfile" ) or die "can't open file: $!\n";

      that will tell you when you try to open the file for writing if you can even do that.
      Your code works fine, it's a file permissions issue, guaranteed.
      You are generating temporary files with invalid names and ignoring the function return code of open(). You should not use the following code, but use one of the temporary filename creation methods available in CPAN modules (perhaps IO::File->new_tmpfile(), but there is probably a better one).
      use strict; use warnings; my $localtime = scalar localtime; my $tmp = ".txt"; my $logfile = $localtime.$tmp; $logfile =~ tr/ /-/; open( OUTFILE, ">$logfile" ) or die "couldn't open $logfile\:$!\n"; print OUTFILE "Hello"; close(OUTFILE)

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://287104]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others exploiting the Monastery: (4)
As of 2023-01-30 18:54 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found

    Notices?