X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=pod%2Fperlfaq4.pod;h=8d93d3fad6f413e83d3d4ebe7f71fee52a41c444;hb=4ff31b786b9f6148fc8ea695db081861576d06a2;hp=25418d02169493dbaa12de4df1c42738de023a78;hpb=f449fe8af429114912b627758de5588f04953ecc;p=p5sagit%2Fp5-mst-13.2.git diff --git a/pod/perlfaq4.pod b/pod/perlfaq4.pod index 25418d0..8d93d3f 100644 --- a/pod/perlfaq4.pod +++ b/pod/perlfaq4.pod @@ -1,6 +1,6 @@ =head1 NAME -perlfaq4 - Data Manipulation ($Revision: 8539 $) +perlfaq4 - Data Manipulation =head1 DESCRIPTION @@ -48,35 +48,45 @@ numbers. What you think in the above as 'three' is really more like =head2 Why isn't my octal data interpreted correctly? -Perl only understands octal and hex numbers as such when they occur as -literals in your program. Octal literals in perl must start with a -leading C<0> and hexadecimal literals must start with a leading C<0x>. -If they are read in from somewhere and assigned, no automatic -conversion takes place. You must explicitly use C or C if you -want the values converted to decimal. C interprets hexadecimal (C<0x350>), -octal (C<0350> or even without the leading C<0>, like C<377>) and binary -(C<0b1010>) numbers, while C only converts hexadecimal ones, with -or without a leading C<0x>, such as C<0x255>, C<3A>, C, or C. -The inverse mapping from decimal to octal can be done with either the -<%o> or C<%O> C formats. +(contributed by brian d foy) + +You're probably trying to convert a string to a number, which Perl only +converts as a decimal number. When Perl converts a string to a number, it +ignores leading spaces and zeroes, then assumes the rest of the digits +are in base 10: + + my $string = '0644'; + + print $string + 0; # prints 644 + + print $string + 44; # prints 688, certainly not octal! + +This problem usually involves one of the Perl built-ins that has the +same name a unix command that uses octal numbers as arguments on the +command line. In this example, C on the command line knows that +its first argument is octal because that's what it does: + + %prompt> chmod 644 file + +If you want to use the same literal digits (644) in Perl, you have to tell +Perl to treat them as octal numbers either by prefixing the digits with +a C<0> or using C: -This problem shows up most often when people try using C, -C, C, or C, which by widespread tradition -typically take permissions in octal. + chmod( 0644, $file); # right, has leading zero + chmod( oct(644), $file ); # also correct - chmod(644, $file); # WRONG - chmod(0644, $file); # right +The problem comes in when you take your numbers from something that Perl +thinks is a string, such as a command line argument in C<@ARGV>: -Note the mistake in the first line was specifying the decimal literal -C<644>, rather than the intended octal literal C<0644>. The problem can -be seen with: + chmod( $ARGV[0], $file); # wrong, even if "0644" - printf("%#o",644); # prints 01204 + chmod( oct($ARGV[0]), $file ); # correct, treat string as octal -Surely you had not intended C - did you? If you -want to use numeric literals as arguments to chmod() et al. then please -try to express them as octal constants, that is with a leading zero and -with the following digits restricted to the set C<0..7>. +You can always check the value you're using by printing it in octal +notation to ensure it matches what you think it should be. Print it +in octal and decimal format: + + printf "0%o %d", $number, $number; =head2 Does Perl have a round() function? What about ceil() and floor()? Trig functions? @@ -363,7 +373,7 @@ pseudorandom generator than comes with your operating system, look at =head2 How do I get a random number between X and Y? To get a random number between two values, you can use the C -builtin to get a random number between 0 and 1. From there, you shift +built-in to get a random number between 0 and 1. From there, you shift that into the range that you want. C returns a number such that C<< 0 <= rand($x) < $x >>. Thus @@ -373,7 +383,7 @@ from 0 to the difference between your I and I. That is, to get a number between 10 and 15, inclusive, you want a random number between 0 and 5 that you can then add to 10. - my $number = 10 + int rand( 15-10+1 ); + my $number = 10 + int rand( 15-10+1 ); # ( 10,11,12,13,14, or 15 ) Hence you derive the following simple function to abstract that. It selects a random integer between the two given @@ -478,6 +488,9 @@ Julian day) 31 =head2 How do I find yesterday's date? +X X X X X +X X X X +X (contributed by brian d foy) @@ -504,6 +517,22 @@ dates, but that assumes that days are twenty-four hours each. For most people, there are two days a year when they aren't: the switch to and from summer time throws this off. Let the modules do the work. +If you absolutely must do it yourself (or can't use one of the +modules), here's a solution using C, which comes with +Perl: + + # contributed by Gunnar Hjalmarsson + use Time::Local; + my $today = timelocal 0, 0, 12, ( localtime )[3..5]; + my ($d, $m, $y) = ( localtime $today-86400 )[3..5]; + printf "Yesterday: %d-%02d-%02d\n", $y+1900, $m+1, $d; + +In this case, you measure the day starting at noon, and subtract 24 +hours. Even if the length of the calendar day is 23 or 25 hours, +you'll still end up on the previous calendar day, although not at +noon. Since you don't care about the time, the one hour difference +doesn't matter and you end up with the previous date. + =head2 Does Perl have a Year 2000 problem? Is Perl Y2K compliant? Short answer: No, Perl does not have a Year 2000 problem. Yes, Perl is @@ -781,14 +810,33 @@ result to a scalar, producing a count of the number of matches. $count = () = $string =~ /-\d+/g; =head2 How do I capitalize all the words on one line? +X X X X + +(contributed by brian d foy) + +Damian Conway's L handles all of the thinking +for you. + + use Text::Autoformat; + my $x = "Dr. Strangelove or: How I Learned to Stop ". + "Worrying and Love the Bomb"; + + print $x, "\n"; + for my $style (qw( sentence title highlight )) { + print autoformat($x, { case => $style }), "\n"; + } -To make the first letter of each word upper case: +How do you want to capitalize those words? - $line =~ s/\b(\w)/\U$1/g; + FRED AND BARNEY'S LODGE # all uppercase + Fred And Barney's Lodge # title case + Fred and Barney's Lodge # highlight case -This has the strange effect of turning "C" into "C". Sometimes you might want this. Other times you might need a -more thorough solution (Suggested by brian d foy): +It's not as easy a problem as it looks. How many words do you think +are in there? Wait for it... wait for it.... If you answered 5 +you're right. Perl words are groups of C<\w+>, but that's not what +you want to capitalize. How is Perl supposed to know not to capitalize +that C after the apostrophe? You could try a regular expression: $string =~ s/ ( (^\w) #at the beginning of the line @@ -799,34 +847,8 @@ more thorough solution (Suggested by brian d foy): $string =~ s/([\w']+)/\u\L$1/g; -To make the whole line upper case: - - $line = uc($line); - -To force each word to be lower case, with the first letter upper case: - - $line =~ s/(\w+)/\u\L$1/g; - -You can (and probably should) enable locale awareness of those -characters by placing a C pragma in your program. -See L for endless details on locales. - -This is sometimes referred to as putting something into "title -case", but that's not quite accurate. Consider the proper -capitalization of the movie I, for example. - -Damian Conway's L module provides some smart -case transformations: - - use Text::Autoformat; - my $x = "Dr. Strangelove or: How I Learned to Stop ". - "Worrying and Love the Bomb"; - - print $x, "\n"; - for my $style (qw( sentence title highlight )) { - print autoformat($x, { case => $style }), "\n"; - } +Now, what if you don't want to capitalize that "and"? Just use +L and get on with the next problem. :) =head2 How can I split a [character] delimited string except when inside [character]? @@ -980,7 +1002,7 @@ appear as part of the data. If you want to work with comma-separated values, don't do this since that format is a bit more complicated. Use one of the modules that -handle that fornat, such as C, C, or +handle that format, such as C, C, or C. If you want to break apart an entire line of fixed columns, you can use @@ -1006,12 +1028,15 @@ C, and C modules. (contributed by brian d foy) If you can avoid it, don't, or if you can use a templating system, -such as C or C