11 Replies Latest reply on Feb 16, 2016 5:55 AM by Klaus Göbel

    Replace string with formatted text

    K.Daube Level 1

      Dear all - I'm back to my beloved project...

      I want to replace a found string by a TextSelction (formatted text) and started with Jang’s famous function  FindAndReplaceString.
      Since my replacement comes from a different document (sourceDoc)  I edited activeDoc to targetDoc and introduced a second document (sourceDoc).
      Actually the replacePara comes from an arry where it had been placed to avoid switching back and forth between the documents of a book (where to find and replace) and the source documents. I have learnt in another function that the information on the array requires that the sourceDoc must stay open.

      • Of course everything works fine until I want to insert the replacelement:
        line 26 clears the found string
      • Since I do not insert a string, I skip lines 28 and 29 and try try line 30
      • At line 30 sourceDoc is object Document and replacePare is object TextSelection. However, sourceDoc.replacePara is undefined and
      • (as a consequence ?) line 31 pasts the current clipboard contents.

      Obviously there is some fog around me ... and I need some sunshine.

       

      function FindAndReplacePara (targetDoc, findString, sourceDoc, replacePara, loopMax) {
        var tr = new TextRange();
        var restoreTR, frame = 0, loopCounter = 0, replacementCounter = 0;
        var findParams = new PropVals();
        var firstPgf = targetDoc.MainFlowInDoc.FirstTextFrameInFlow.FirstPgf;
        
        tr.beg.obj = tr.end.obj = firstPgf;             //  set up the starting text range as the very beginning
        tr.beg.offset = tr.end.offset = 0;              // of the flow. We'll move straight from beginning to end.
        trSaved = tr                                    // to come back after work
      
        findParams = AllocatePropVals(2);
        
        findParams[0].propIdent.num = Constants.FS_FindText;
        findParams[0].propVal.valType = Constants.FT_String;
        findParams[0].propVal.sval = findString;
        
        findParams[1].propIdent.num = Constants.FS_FindCustomizationFlags;
        findParams[1].propVal.valType = Constants.FT_Integer;
        findParams[1].propVal.ival = Constants.FF_FIND_CONSIDER_CASE;
      
        FA_errno = Constants.FE_Success;                // errno global, to be used to track the progress of the find and replace
        tr = targetDoc.Find(tr.beg, findParams);        // and do an initial find to get started.
        
        while(FA_errno === Constants.FE_Success && loopCounter++ < 2*loopMax) { //find and replace loop as long as we keep finding
          targetDoc.TextSelection = tr;                 // set up the text range to clear the original text
          targetDoc.Clear(0);                           // clear it
          
      //    targetDoc.AddText(tr.beg, replacePara);       // insert the new text at the original beginning of the text range
      //    tr.beg.offset += replacePara.length;          //  lets jimmy the text range in memory to place it directly after
          targetDoc.TextSelection = sourceDoc.replacePara;        // paste the whole replacement paragraph
          targetDoc.Paste (0);                          // <-- Current contents of clipboard is pasted !!!!
          if(FA_errno === Constants.FE_Success) {       // increment our return counter
            replacementCounter++;
          }
          FA_errno = Constants.FE_Success;              // ...  find the next instance. We'll reset FA_errno again just in case
          tr = targetDoc.Find(tr.beg, findParams);      // something screwy happened while we were replacing text.
        }
        targetDoc.ScrollToText(trSaved);                // we're done. Restore the document to it's original area of display
        return replacementCounter;
      } // --- end FindAndReplacePara
      
        • 1. Re: Replace string with formatted text
          Russ Ward Level 4

          Hi Klaus,

           

          I see dense fog around line 30   As best I can tell, this is a completely invalid statement:

           

          targetDoc.TextSelection = sourceDoc.replacePara;

           

          A text selection is a data structure that consists of a start point and an end point, where each point consists of a paragraph object and an offset. These objects must be members of the parent document itself. It doesn't make any sense to assign paragraph objects from another document to a text range. It would be like me giving out directions to the US White House, using a map of Moscow. No logical correlation anywhere in that. Furthermore, like I mentioned, a text range is a data structure with multiple objects. So it doesn't make sense to assign a single paragraph object to it. Furtherfurthermore, "sourceDoc.replacePara" is an invalid expression by itself, because there is no "replacePara" property of a document object. These are two separate variables passed in the function arguments.

           

          You did mention that "replacePara" is a "TextSelection" object, so maybe my second point is invalid. But I'm not sure... your variable name suggests that it is a paragraph object. Also, there is no such thing as a TextSelection object, perhaps you meant a TextRange object? In any case, I am sure that points 1 and 3 are correct.

           

          Anyway, now that I've sufficiently trashed line 30, perhaps you could elaborate on what you really want to do. Are you simply trying to copy a paragraph (or part of a paragraph) from sourceDoc into the Find locations in targetDoc? And could you clarify what kind of variable "replacePara" really is?

           

          I think we can get this to work with minimal effort... I just see some need for clarification.

           

          Russ

          • 2. Re: Replace string with formatted text
            K.Daube Level 1

            Thanks Russ for the answer - so I stepped back and first tried to just paste the data as string. This works perfectly thanks the function GetText (by Rick) which I use frequently in my script.

             

            The relevant part in the script now is this:

              targetDoc.TextSelection = tr;                 // set up the text range to clear the original text
              targetDoc.Clear(0);                           // clear it
              replaceString = GetText (replacePara, sourceDoc); // expects TextObject, Doc
              targetDoc.AddText(tr.beg, replaceString);     // insert the new text at the original beginning of the text range
              tr.beg.offset += replaceString.length;        // lets jimmy the text range in memory to place it directly after
            
            

             

            But how can I insert the formatted text which is in the variable replacePara? replacePara is (watch the italic portion):

            Müller, P. D. H. (1925). De viris illustribus, Carl Meyer (Gustav Prior), Hannover.

             

            BTW: know what 'to jimmy' is: apply some brute force. IMHO special words protect against plagiarism...

            I always keep the sources mentioned. In this functions it is

            // Source: script by Russ Ward in https://forums.adobe.com/message/3888653#3888653
            
            • 3. Re: Replace string with formatted text
              Russ Ward Level 4

              Klaus, I got an email from the forum with a post from you, but I don't see it here on the web page. I'll answer it anyway.

               

              I can't figure out what you mean by "formatted text which is in the variable replacePara". What is "formatted text"? A variable cannot contain formatted text, at least the way you seem to be thinking. I need to know how you are setting replacePara and what type of variable it is.

               

              My suspicion is that you just want to copy from the source document and paste to the target document. In that case, you need to set the text selection in the source doc, call sourceDoc.Copy() (with the source doc active, probably), activate the target doc, then targetDoc.Paste().

               

              And by the way, "jimmy" is an excellent plagiarism detector. That's how I know the source code was originally from me. If Jang tried to swipe it, well, that dirty rat, totally busted.

               

              Russ

              • 4. Re: Replace string with formatted text
                K.Daube Level 1

                Russ, the explanation of variable replacePara is somewhat lenghty:

                «My suspicion is that you just want to copy from the source document and paste to the target document. In that case, you need to set the text selection in the source doc, call sourceDoc.Copy() (with the source doc active, probably), activate the target doc, then targetDoc.Paste().» is correct in principle, but...


                The pupose of the discussed part of the script is to replace placeholders (such as {Barnes-Ellerbe, 2004 #48}) in targetDoc with complete references (such as Barnes-Ellerbe, S., Knudsen, K. E., and Puga, A. (2004). "2,3,7,8-Tetrachlorodibenzo-p-dioxin blocks androgen-dependent cell proliferation of LNCaP cells through modulation of pRB phosphorylation." Mol Pharmacol, 66(3), 502-11.) from a sourceDoc (note the italic part in this text - this i call formatted text, ince the whole thing can not be treated just as string).
                Since the placeholders are located in various documents of a book, the information from the document with the replacement texts (sourceDoc ) is filled into arrays. Otherwise I would need to switch between the targetDoc/oDoc2 and sourceDoc/oDoc1 for each reference in the sourceDoc. BTW this sourceDoc is an RTF created by a bibliographic application (EndNote or Citavi) and opened in FM, hence a standard fm document.
                I have 3 global arrays:

                var gasFmtCitsRaw  = [];                        // left column in processed RTF
                var gasFmtCitsFmt  = [];                        // right column in processed RTF
                var gaoBibliography = [];                        // bibliography paragraphs from processed RTF
                


                They are filled in function GetBiblioFromRTF with the following statements relevant for replacePara:

                // --- read the bibliography paragraphs
                  while (pgf.ObjectValid()) {                    // until end of doc
                    tabRange = GetTabRange (pgf, goRtfDoc);      // Get the text range starting after the TAB to the end of the paragraph. 
                    if (tabRange) { 
                    gaoBibliography.push(tabRange);              // store the paragraph-part in the array
                    pgf = pgf.NextPgfInFlow;
                    } else { break }                              // We are out of the bibliography range
                  }
                


                Then in a loop the find/replace operation is performed:

                function ExpandInDoc (oDoc2, oDoc1) {
                // oDoc2 target document where to replace
                // oDoc1 source document of the replacements in the array
                  var j, jBiblio, nBiblio, nCitations, findString, replacePara, loopMax, overallCounter = 0;
                  var nCitations = gasFmtCitsRaw.length;
                  var loopMax = nCitations;
                  for (j = 0; j < nCitations; j += 1) {
                    findString    = gasFmtCitsRaw[j];
                    jBiblio      = gasFmtCitsFmt[j];            // number of biblio-paragraph
                    replacePara = gaoBibliography[jBiblio-1];    // is object TextRange 
                    replacementCounter = FindAndReplacePara (oDoc2, findString, oDoc1, replacePara, loopMax); 
                  }
                } // --- end ExpandInDoc
                


                IMHO replacePara is a TextRange which contains formatted text (string pieces with character formats forming part of a paragraph).

                Then function FindAndReplacePara comes into play.

                I hope this will explain the nature of replacePara.

                • 5. Re: Replace string with formatted text
                  Russ Ward Level 4

                  Hi Klaus,

                   

                  Thanks for the explanation. I remember that GetTabRange stuff from way back. You have been quite patient and persistent with this project, indeed.

                   

                  So, given that we are dealing with text ranges here, I think that the only simple approach is to perform a copy/paste. There is no way to save a "formatted string" in a variable. The only super-precise way would be to get a TextItems data structure from each text range in the sourceDoc, then meticulously recreate each item in the targetDoc. This would be wildly complicated, I think, so a copy/paste seems the most logical. I'm wondering, though, if I'm missing something, because I think maybe you would have tried it already if so (?)

                   

                  Anyway, I would do something like this, starting at line 30 of your original code sample (untested code here):

                   

                  app.ActiveDoc = sourceDoc;

                  sourceDoc.TextSelection = replacePara;

                  sourceDoc.Copy(0);

                  app.ActiveDoc = targetDoc;

                  targetDoc.Paste(0);

                   

                  ... etc.

                   

                  Does this make sense, or am I barking up the wrong tree, as they say?

                   

                  Russ

                  • 6. Re: Replace string with formatted text
                    K.Daube Level 1

                    Wow! Russ, that's a real break-trhough!

                    This does exactly what I want to achieve!

                    Now I see the end of the tunnel for my project.

                     

                    I had experimented with copy and paste but obviously did not get it right - my knowledge of the object model still is in anfant state...

                    • 7. Re: Replace string with formatted text
                      Russ Ward Level 4

                      Klaus, I'm happy to hear that. Regarding the copy/paste, it is my assumption that you have to make the source and target documents active before you do the copy and paste, respectively. Even though the Copy() and Paste() methods are assigned to the document object, I don't believe that they will just work independently. In the FDK, they were "global" functions that didn't need any document object... it was up to you to make whichever document active, just like working in the GUI. Anyway, the documentation doesn't say this anywhere, just my guess. I'd be interested to know if you could validate that.

                       

                      Russ

                      • 8. Re: Replace string with formatted text
                        K.Daube Level 1

                        Russ, it works perfectly, as you can see from this Captivate Flash.

                        What I have noted after that captureing is this: Although the ¶ format of the Footnote in the target file has no * in the information area, the format is not correct. Re-applying format Footnote lets the size shrink. Only the 'not expanded' footnotes starting with a { keep their format.

                        But this can be fixed by re-applying the format of the footnote.

                        The reason propably is that in the sourceDoc (coming from an RTF generated by the biblogrphic app) uses a format named HeadingRunIn with different properties. The effect will be even more visible, if I have a targetDoc with sans-serif styles...

                        • 9. Re: Replace string with formatted text
                          Klaus Göbel Level 3

                          FA_errno = Constants.FE_Success;                // errno global, to be used to track the progress of the find and rep

                          Hi Klaus,

                           

                          FA_errno is write-protected. This should result in an error message.

                          • 10. Re: Replace string with formatted text
                            Russ Ward Level 4

                            Hi Klaus and Klaus,

                             

                            It is true (and unfortunate) that FA_errno is write-protected. With the FDK, it was common practice to reset it in certain circumstances. Nonetheless, there are tricks to do the same thing with ExtendScript. Here is a thread that shows one:

                             

                            Are there situations where you can NOT override the FA_errno's code?

                             

                            Russ

                            • 11. Re: Replace string with formatted text
                              Klaus Göbel Level 3

                              Hi Russ,

                               

                              thanks for this link.

                               

                              This is exactly what I am doing. I use :

                              var openParams = GetOpenDefaultParams();

                              It results in FA_errno = 0 and works fine.