3dbc has asked for the wisdom of the Perl Monks concerning the following question:

Hello Fellow Monks, It's been a while, but haven't lost my love for this language and glad to be back.

Problem:

Basically my issue is that I want to write scalars in replace of the tokens, but my scalar is over 255 characters.

Background:

Basically what I'm working on is a big perl script to scour a bunch of data and aggregate it into hundreds of word docs. I'm using a template doc by identifying substitutions within the template as ##token_strings##, searching for them and replacing them. I think this approach would be helpful to anyone trying to automate the generation of word documents based on a predefined template with perl. A template is a doc you've already formatted with all the bells and whistles you need, but then need to mass produce them based on the script.

Further Details:

One of my buggy problems is that I'm having a weird win32 error when trying to replace Microsoft Word text strings with strings greater than 255 characters, any ideas on an alternative approach?

Trying to do the following and hit an issue with scalar size
my $doc = $Word->Documents->Open($_[0]) || die("Unable to open documen +t ", Win32::OLE->LastError()); # Open document #my $doc = $MSWord->Documents->Open({FileName=>$_[0]}); # Exit nicely if we couldn't open doc return unless $doc; # Content object my $content=$doc->Content; #my $selection = $word->Selection; print "Finding Tokens...\n"; # Find object my $find=$content->Find; $find->ClearFormatting; $find->{Text}="##TOKEN_REPLACE##"; $find->Replacement->ClearFormatting; $find->Replacement->{Text}=$cant_be_more_than_255
Below is a code snippet, not complete script, but if you know Win32::ole I think it should make sense what my problem is, but please do let me know if you have any questions. I have the error it generates too if that's helpful, i.e. when it's not within the if / else and perl tries to write the scalar which is over 255 chars.
if (length($service_screens) > 255) { print "These are $service_screens string is over 255 \n\n" +; $find->ClearFormatting; $find->{Text}="##TOKEN_REPLACE##"; $find->Replacement->ClearFormatting; $find->Replacement->{Text}="Service Screens"; #$doc->ActiveWindow->Selection->MoveDown(wdLine,1); #$doc->ActiveWindow->Selection->TypeText("Can't write scal +ar because it's over 255 chars??"); $find->Execute({Replace=>$wd->{wdReplaceAll},Forward=>$wd- +>{True}}); } else { $find->ClearFormatting; $find->{Text}="##TOKEN_REPLACE##"; $find->Replacement->ClearFormatting; $find->Replacement->{Text}=$service_screens; #$doc->ActiveWindow->Selection->MoveDown(wdLine,1); #$doc->ActiveWindow->Selection->TypeText("This line should + be after the Service screen"); $find->Execute({Replace=>$wd->{wdReplaceAll},Forward=>$wd- +>{True}}); }
Thanks.
- 3dbc

Replies are listed 'Best First'.
Re: Win32 ->Replacement->{Text} more than 255 characters
by kcott (Archbishop) on Jan 25, 2017 at 07:18 UTC

    G'day 3dbc,

    Welcome back!

    I don't have access to your platform (Win32::* modules, "MSWord", etc.) but, as I see no one has replied in over eight hours, here's at least a technique you could use, to split your replacement string into smaller parts, and then do multiple replacements.

    #!/usr/bin/env perl use strict; use warnings; use constant { MAX_STR_LEN => 5, TOKEN => '#T#', }; use Test::More; my @tests = ( ['#T#', 'abc', 'abc'], ['#T#', 'abcd', 'abcd'], ['#T#', 'abcde', 'abcde'], ['#T#', 'abcdef', 'abcdef'], ['#T#', 'abcdefg', 'abcdefg'], ['#T#', 'abcdefghijklm', 'abcdefghijklm'], ['', 'abcdefghijklm', ''], ['xyz', 'abcdefghijklm', 'xyz'], ['MNO #T# PQR', 'abcdefghijklm', 'MNO abcdefghijklm PQR'], ['MNO#T# PQR', 'abcdefghijklm', 'MNOabcdefghijklm PQR'], ['MNO #T#PQR', 'abcdefghijklm', 'MNO abcdefghijklmPQR'], ['MNO#T#PQR', 'abcdefghijklm', 'MNOabcdefghijklmPQR'], ['MNO##T##PQR', 'abcdefghijklm', 'MNO#abcdefghijklm#PQR'], ); plan tests => scalar @tests; for (@tests) { my ($target, $replace, $expect) = @$_; my $newstr = $target; my @replacements; if (index($newstr, TOKEN) != -1) { for (my $pos = 0; $pos < length $replace; $pos += MAX_STR_LEN) + { push @replacements, substr $replace, $pos, MAX_STR_LEN; } for my $replacement (@replacements) { substr $newstr, index($newstr, TOKEN), 0, $replacement; } substr $newstr, index($newstr, TOKEN), length TOKEN, ''; } is($newstr, $expect, "'$target' -> '$expect'"); }

    Output:

    1..13 ok 1 - '\#T\#' -> 'abc' ok 2 - '\#T\#' -> 'abcd' ok 3 - '\#T\#' -> 'abcde' ok 4 - '\#T\#' -> 'abcdef' ok 5 - '\#T\#' -> 'abcdefg' ok 6 - '\#T\#' -> 'abcdefghijklm' ok 7 - '' -> '' ok 8 - 'xyz' -> 'xyz' ok 9 - 'MNO \#T\# PQR' -> 'MNO abcdefghijklm PQR' ok 10 - 'MNO\#T\# PQR' -> 'MNOabcdefghijklm PQR' ok 11 - 'MNO \#T\#PQR' -> 'MNO abcdefghijklmPQR' ok 12 - 'MNO\#T\#PQR' -> 'MNOabcdefghijklmPQR' ok 13 - 'MNO\#\#T\#\#PQR' -> 'MNO\#abcdefghijklm\#PQR'

    — Ken

Re: Win32 ->Replacement->{Text} more than 255 characters
by poj (Abbot) on Jan 25, 2017 at 10:03 UTC
    any ideas on an alternative approach

    You could search for and delete the token then insert the new text

    #!perl use strict; use Win32::OLE; use Win32::OLE::Const 'Microsoft Word'; $Win32::OLE::Warn = 3; my $word = Win32::OLE->new('Word.Application', 'Quit') or die; $word->{Visible} = 1; $word->{DisplayAlerts} = 0; my $doc = $word->Documents->Open({FileName => "c:/temp/Word.doc"}); my $sel = $word->Selection; $sel->Find->{Forward} = 1; $sel->Find->{MatchWholeWord} = 1; for my $n (1..2){ $sel->Find->{Text} = '##TOKEN'.$n.'##'; $sel->Find->Execute; $sel->Delete; $sel->InsertAfter("($n) This is line 1 of some new text that is more + than 255 characters. This is line 2 of some new text that is more than 255 characters. This is line 3 of some new text that is more than 255 characters. This is line 4 of some new text that is more than 255 characters. This is line 5 of some new text that is more than 255 characters. This is line 6 of some new text that is more than 255 characters. This is line 7 of some new text that is more than 255 characters. This is line 8 of some new text that is more than 255 characters."); $sel->MoveDown({Count=>1}); }; $doc->SaveAs({FileName => 'c:/temp/Word1.doc'}); $doc->Close();
    poj
      Thanks so much Monks for welcoming me back. Couldn't resist using my old account because I'm only 100 points away from being titled a Monk! I think this last post is exactly what I was looking for... I'm not sure you can do multiple replacements with that win32 ole method? Giving it a shot now. THANK YOU

      Also wanted to provide the error message returned in case anyone is searching for this on this site or through google by the error code.

      Win32::OLE(0.1712) error 0x80020009: "Exception occurred" in PROPERTYPUT "Text" at evolveIT2.pl line 193. OLE exception from "Microsoft Word": String parameter too long.