http://www.perlmonks.org?node_id=999325


in reply to Re: Increaing a field size for a record
in thread Increaing a field size for a record

There's no magic that would allow expand field in place.

What? No magic? But this is Perl — of course there’s magic!

#! perl use strict; use warnings; use Tie::File; my $filename = 'data.txt'; tie my @lines, 'Tie::File', $filename or die "Cannot tie file '$filen +ame' to array: $!"; for (my $i = 0; $i < @lines; ++$i) { my @fields = split ' ', $lines[$i]; $fields[1] .= ' ' x (50 - length $fields[1]); $lines[$i] = join(' ', @fields); } untie @lines;

Test file “data.txt” before running the script:

DSE 1232123456 ABCDEF96DS0 20100722 20120827KJHLK LKEDX 058305574 IAC +8 S73 WERTYU DSE 987 ABCDEF96DS0 20100722 20120827KJHLK LKEDX 058305574 IAC 8 S73 W +ERTYU DSE 12321234567890 ABCDEF96DS0 20100722 20120827KJHLK LKEDX 058305574 +IAC 8 S73 WERTYU

and after:

DSE 1232123456 ABCDEF96DS0 201 +00722 20120827KJHLK LKEDX 058305574 IAC 8 S73 WERTYU DSE 987 ABCDEF96DS0 201 +00722 20120827KJHLK LKEDX 058305574 IAC 8 S73 WERTYU DSE 12321234567890 ABCDEF96DS0 201 +00722 20120827KJHLK LKEDX 058305574 IAC 8 S73 WERTYU

;-)

Athanasius <°(((><contra mundum

Replies are listed 'Best First'.
Re^3: Increasing a field size for a record
by zwon (Abbot) on Oct 16, 2012 at 15:38 UTC

    That's a funny approach, but is not very efficient, every time you're assigning to $line[$i] it rewrites all the file starting from the record $i.

    Update: More efficient would be to use File::Slurp:

    use strict; use warnings; use File::Slurp qw(edit_file_lines); sub fix { my @fields = split / +/; $fields[1] = sprintf "%-50s", $fields[1]; $_ = join ' ', @fields; } edit_file_lines \&fix, $file_name;
    The problem is that it doesn't preserve the width of the other fields
Re^3: Increasing a field size for a record
by McA (Priest) on Oct 16, 2012 at 13:31 UTC

    Hi Athanasius,

    very interesting inline approach. But is it really necessary to use this "un-perl-ish" ;-) C-construct  for (my $i = 0; $i < @lines; ++$i)? Does it also work with a foreach-loop or is then the inline editing broken?

    Best regards
    McA

      If it works and is effortless to understand ... as the original construct does and is ... then I would give it no more time than that.

      You should write your program, not only to reformat the file but also to sanity-check its own results.   For example, if you can assert that the line should contain exactly, say, 11 groups, then your program should make that assertion, and it should die if it does not.   If you can say that (especially, nearby) fields should be of a certain form that can be checked by a regex, make that check.

      The reason is that, if there is a problem either with the file or with the program ... or if there has been some subtle change such that this program’s underlying assumptions no longer hold true as-written, then no human is likely to detect the problem.   But the software is in an ideal position to do so.

      Good point! After a little experimentation, it appears that the following also works:

      for my $line (@lines) { my @fields = split ' ', $line; $fields[1] .= ' ' x (50 - length $fields[1]); $line = join(' ', @fields); }

      Thanks, nice catch!

      Athanasius <°(((><contra mundum

Re^3: Increasing a field size for a record
by Thomas Kennll (Acolyte) on Oct 16, 2012 at 17:59 UTC
    Thanks Athanasius! That was really halpful I got a problem, the positions are not space separated, If I insert 39 spaces from postion 15 in all records will help.. how can I do that ?

      Hello Thomas Kennll,

      It seems you’ve re-written your original question. Please don’t do that! It makes it difficult for anyone who tries to follow the thread — besides making it very confusing for those trying to help you. See the recent posting On node obliteration.

      In a previous post you say the fields are space separated, now they’re not? Then how do you distinguish one field from the next? Also, you say you want to insert spaces “from pos[i]tion 15 in all records”, but in the data originally shown, none of the fields was more than 13 characters long. You will need to provide sample data showing the way fields are set out on each line. (And please remember to enclose the data in <code> </code> tags.)

      As for inserting spaces (or any other string) into an existing string, you can use substr, as shown by flexvault below.

      Athanasius <°(((><contra mundum

        Thanks for your help Athanasius! I missed to notice that I wiped away the initial question.. Will take care of that!!