How to append a file accordingly?

W

Why Tea

How to append to a text file based on the following conditions:
1) if the last characters of the file are "\n" or "\r\n", simply
print FH "$some_text";
2) if the last characters are none of "\n" or "\r" or "\r\n", do
print FH "\n$some_text";

/Why Tea
 
W

Why Tea

Maybe this way?

if($some_text =~ m/(\r\n|\n|\r)$/s)
{
print FH "$some_text";
}
else
{
print FH "\n$some_text";
}

Petr, your code checks for white spaces at the end of $some_text, but
I was talking about white spaces at the end of the opened file, i.e.
open(FH, $some_file)
 
S

Spiros Denaxas

Petr, your code checks for white spaces at the end of $some_text, but
I was talking about white spaces at the end of the opened file, i.e.
open(FH, $some_file)

Why Tea,

I believe Petr's solution involves slurping the file and then
checking.
You could use:

File::Slurp http://search.cpan.org/perldoc?Perl6::Slurp
Perl6::Slurp http://search.cpan.org/perldoc?File::Slurp

How big is the file? I believe this is a crucial factor since
for very long and/or large files, the majority of common methods
might not be applicable.

Spiros
 
P

Peter Makholm

Why Tea said:
How to append to a text file based on the following conditions:
1) if the last characters of the file are "\n" or "\r\n", simply
print FH "$some_text";
2) if the last characters are none of "\n" or "\r" or "\r\n", do
print FH "\n$some_text";

Untested and without error handling:

use Fcntl qw:)seek);

my $last;
open my $fh, '+<', $filename;
seek $fh, -1, SEEK_END;
read $fh, $last, 1;
seek $fh, 0, SEEK_END; # Probably not needed.

print {$fh} "\n" unless $last eq "\n";
print {$fh} $some_text;
 
T

Tad McClellan

Petr Vileta said:
if($some_text =~ m/(\r\n|\n|\r)$/s)
^
^

the m//s modifier is a no-op for that regex.

You should not use modifiers that do not do any modification...
 
W

Why Tea

I assumed that whole file content is in $some_text. When you can read file
line by line then you can use this

open FH "< $myfile";
binmode FH; # not need for *nix systems
seek FH, -2, 2; # seek for last 2 bytes
my $lastchars = <FH>;
close FH;
open FH "< $myfile";
while (my $row = <FH>)
{
print $row;
}
close FH;
print "\n" unless($lastchars =~ m/(\r\n|\n|\r)$/s)
--

Thanks Petr. The code works fine in detecting \r\n|\n|\r, but it fails
when the $lastchars are just normal characters. What I did was to
append a line of text to the file and I didn't want to have a blank
line if there is already \r\n|\n|\r. I ran your code once, it was OK
but the subsequent runs failed (I expected \n to be printed, but it
didn't).

/Why Tea
 
B

Ben Morrow

Use three-arg open.
Use lexical filehandles.
Check the open succeeded.

Yes, it is *always* needed as of 5.8. You can also combine this step
with the open:

open my $FH, '<:raw', $myfile
or die "can't read '$myfile': $!";

Don't use magic numbers for seek. Use the proper constants: it's
clearer, and safer if you ever port the code to a machine where SEEK_END
isn't 2 (such things do happen: GNU Hurd, for instance, has O_RDONLY
defined as 1 rather than 0).

use Fcntl qw/:seek/;

seek $FH, -2, SEEK_END;

Why do this? It just introduces an entirely unnecessary race condition,
and you haven't reopened it in binary mode, which may or may not be
important. If you wish to reinstate CRLF processing, you can say

binmode $FH, ':crlf';

It's not clear the OP wants to copy the file. If he wants to append, it
would be better to open in '+<' mode seek to the end before writing.

While I'm usually a fan of using regexes rather than more low-level
solutions, this is more complicated than necessary. Something like

seek $FH, -1, SEEK_END;
or die "can't seek '$myfile': $!";
read $FH, my $eol, 1
or die "can't read from '$myfile': $!";

seek $FH, 0, SEEK_END;
print $FH "\n" unless $eol =~ tr/\r\n//;

would be simpler. If you want to insert a newline matching the rest of
the file, you would need to read at least two characters, of course. For
normalizing newlines see PerlIO::eol.

Note also that "\r" and "\n" are not portable. Some systems have "\r" eq
"\012" and "\n" eq "\015". If you mean an ASCII CR say "\015".
Thanks Petr. The code works fine in detecting \r\n|\n|\r, but it fails
when the $lastchars are just normal characters. What I did was to
append a line of text to the file and I didn't want to have a blank
line if there is already \r\n|\n|\r. I ran your code once, it was OK
but the subsequent runs failed (I expected \n to be printed, but it
didn't).

It works for me here. Please post a complete script that shows how it
fails.

Note that text files *should* end with a trailing newline (in the
appropriate local format). If you have files that don't, they're
arguably broken, and you're better off fixing them than propagating the
error.

Ben
 
T

Tad McClellan

Abigail said:
_
Tad McClellan ([email protected]) wrote on VCC September MCMXCIII in
<URL::)
:) > if($some_text =~ m/(\r\n|\n|\r)$/s)
:) ^
:) the m//s modifier is a no-op for that regex.
:)
:) You should not use modifiers that do not do any modification...


Hmmmpf.


Although I don't necessarely disagree with you, I don't think such
posts are useful. What might be useful is a reasoning why you think
you shouldn't do so.


My folks often told me "look both ways before you cross the street"
without explaining why I should.


A modifier says "something out of the ordinary is going on here".

Modifiers that don't modify are "crying wolf" to the maintenance programmer.

Preferably also with reasons why people (Damian
for instance, in PBP) do think you should.


I don't really remember why he said to use m//msx, but I think it was
"because they will be enabled by default in Perl 6", ie. to get
yourself ready for Perl 6.

I'll learn Perl 6 when there _is_ a Perl 6 , but while maintaining
Perl 5 code, I'm not going to cry wolf.

(I only have "buy in" for about 80% of the PBP recommendations anyway.)
 
W

Why Tea

It works for me here. Please post a complete script that shows how it

Sorry, I made a mistake. Petr's code actually works. And your code
works fine too, Ben.

Another question, how do you extract the last line of a text file
quickly?

/Why Tea
 
X

xhoster

Tad McClellan said:
My folks often told me "look both ways before you cross the street"
without explaining why I should.

A modifier says "something out of the ordinary is going on here".

Modifiers that don't modify are "crying wolf" to the maintenance
programmer.

On the other hand, you could argue that /sm *is* ordinary, and their
removal is the mark of the unusual. If that is the standard to which the
maintenance programmer is accustomed, than their unwarranted absence would
be what is calling wolf, not their unwarranted presence. Sure, it would
have been nice if Perl had inverted their meanings in the first place, so
that the usual would be shorter than the unusual, but should we be
prisoners to a design flaw when we can just learn a new custom instead?

Xho

--
-------------------- http://NewsReader.Com/ --------------------
The costs of publication of this article were defrayed in part by the
payment of page charges. This article must therefore be hereby marked
advertisement in accordance with 18 U.S.C. Section 1734 solely to indicate
this fact.
 
S

sheinrich

No, that's not the reason. They are by default enabled in Perl6 because
the people developing Perl6 think it's a good idea to have them enabled
by default (and no way to easily turn them off). And for the same reasons
they are on in Perl6, Damian advocates to use them - and to make it easier
for the maintainance programmer, he advocates to turn them always on (that
way, when you see an unescaped '.', '^', '$', '#' or ' ' in a regexp, it
always means the same thing).

I don't buy your argument, and I don't by Damians either. Anyone who
considers /s or /m to be an alarm, or loses track when sometimes /s is
used, and sometimes isn't, shouldn't program Perl in the first place.

Abigail
--
While I share your point of view on the usage of modifiers, I'm afraid
that the outspoken 'perl-enabled' folk's snobbish attitude might be
cause for people feeling rebuffed and for the language's slowly ebbing
popularity.

TIMTOWTDI

Cheers,
Steffen
 

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

Forum statistics

Threads
473,744
Messages
2,569,482
Members
44,901
Latest member
Noble71S45

Latest Threads

Top