• Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
    Dedicated community for Japanese speakers
  • 한국 커뮤니티
    Dedicated community for Korean speakers
Exit
0

How do I use the find method to find multiple items in a single paragraph?

Participant ,
Feb 17, 2012 Feb 17, 2012

Copy link to clipboard

Copied

I am desigining a script to find any instances where ctrl+b and ctrl+i are applied to body text and then replace those character format overrides with Italic or Bold chartag.  Here's what the script is supposed to do:

  1. put the find method in a while loop that searches for character format overrides.
  2. If a character format override is found, pass the text range returned by the find method and the CharPropsChange flag to the GetTextForRange method.
  3. Use a boolean compare between the idata of the text item to the character angle and character weight constants.
  4. Whichever boolean evaluates to true, then use the SetTextProp method to set properties of the text range to the properties of the italic or bold character tag.

This script does work on the first character format override found however it ignores any other overrides in the same paragraph. The cause of this is that the while loop updates the text loc that the find method uses to the next paragraph in flow. I suspect that i need to add an inner loop that goes through all the text in a single paragraph, where at teach iteration the text loc used by the find method is based on the same paragraph but the offset is modified. I am just not sure how to do that.

function removeOverrides (pDoc)

{

    var vDocStart = pDoc.MainFlowInDoc.FirstTextFrameInFlow.FirstPgf;

    var vBoldFmt=getCharFmt (pDoc, 'Bold')

    var vItalicFmt=getCharFmt (pDoc, 'Italic')

    initFA_errno ();

    while (FA_errno==Constants.FE_Success)

    {

        var vTextLoc = new TextLoc(vDocStart,0);

        var vFindParams=findOverrideParams (pDoc);

        var vTextRange=pDoc.Find(vTextLoc,vFindParams);

        if (vTextRange.beg.obj.ObjectValid())

        {

            var vTextItems=pDoc.GetTextForRange (vTextRange, Constants.FTI_CharPropsChange)

            if (vTextItems.length==!0 )

            {

                if (vTextItems[0].idata==Constants.FTF_WEIGHT)

                {

                   pDoc.SetTextProps (vTextRange, vBoldFmt.GetProps())

                    }

                if (vTextItems[0].idata==Constants.FTF_ANGLE)

                {

                   pDoc.SetTextProps (vTextRange, vItalicFmt.GetProps())

                    }

                } else (Log (vLogFileName, '\nERROR: No items were found in the text format array but format override was found: '+pDoc.Name))

            }

        vDocStart=vDocStart.NextPgfInFlow;

        } 

}

function findOverrideParams (pDoc)

{

    var vFindParams = AllocatePropVals(1);

    vFindParams[0].propIdent.num = Constants.FS_FindObject;

    vFindParams[0].propVal.valType = Constants.FT_Integer;

    vFindParams[0].propVal.ival = Constants.FV_FindCharacterFormatOverride;

   return vFindParams;

   }

TOPICS
Scripting

Views

2.7K

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines

correct answers 1 Correct answer

Deleted User
Feb 17, 2012 Feb 17, 2012

Another approach (which is what I've usually done) is after the first search to set vTextLoc = vTextRange.end

Either way, you might consider moving your initializing of vTextLoc and vFindParams outside of the while loop. The parameters don't change, why redefine them for each search?

Votes

Translate

Translate
Engaged ,
Feb 17, 2012 Feb 17, 2012

Copy link to clipboard

Copied

have you tried moving backward through the document.

I don't know if this works for that case but in similar cases, where I delete things in a document, that worked for me

Markus

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Participant ,
Feb 17, 2012 Feb 17, 2012

Copy link to clipboard

Copied

Hi Wiedenmaier,

Tha's a clever idea. I tried it out. Unfortunately it didn't do anything for me. Not sure why though since logically I think that should work. That said Oliver's suggestion about updating the textloc with the end of text range does work. I'd recommend that method if you ever need to use the find method in your scripts.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Guest
Feb 17, 2012 Feb 17, 2012

Copy link to clipboard

Copied

Another approach (which is what I've usually done) is after the first search to set vTextLoc = vTextRange.end

Either way, you might consider moving your initializing of vTextLoc and vFindParams outside of the while loop. The parameters don't change, why redefine them for each search?

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Participant ,
Feb 17, 2012 Feb 17, 2012

Copy link to clipboard

Copied

I feel stupid. It never occurred to me that yes a text range includes two text locations, one of which is the end of the text range that I could use to dynamically update where the find method starts!! Oui, thank you for the pointer. The moment you mentioned it, I had a eureka moment. 

As for the initializing the variables, you are absolutely correct about that. I moved those out of the while loop and that significantly sped up my script. Thanks for that too. As to why I did that, I think its bad scripting habit. I tend to place related things right next to one another, when they should be placed outside loops in order to optimize the script.

One caveat though: the script seems to be working 95% of the time. There's a small subset of the text in the doc, which has bold or italic overrides but the script does not fix.I haven't been able to isolate a pattern though it does tend to happen when the override line breaks within a paragraph. If I can reliably reproduce this inconsistency, I'll update this discussion.

In any case, getting rid of 95% of my overrides and then cleaning up the remaining 5% manually with the find dialog box is still quite worthwhile.

Thanks again. Your insight and advice on scripting is immensely appreciated.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Feb 21, 2012 Feb 21, 2012

Copy link to clipboard

Copied

In general, using the Find method to locate FrameMaker objects is not the best way to go. I have written thousands of FrameScript scripts since 1998, and have probably used Find less than a dozen times. To find tables, you can simply loop through the tables in the document. Or, you can use GetTextItems to get the tables from the main flow in document order. To locate character formatting, you can use GetTextItems on a paragraph to get the character property changes. This takes a bit more code than Find, but it is definitely more reliable and you don't have to manage text ranges and wrapping issues.

Rick

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Participant ,
Feb 21, 2012 Feb 21, 2012

Copy link to clipboard

Copied

Hi Rick,

I actually deleted my table post because I realized I was doing something stupid. The find was returnig a text range where the beg and end objects were one and the same so of course it wasn't ever progressing beyond that point. That was happening because the table was the only thing in the text range.  

That said I see your point now. I was seesawing back and forth between looping through the tables versus doing a find. I was opting for the find because as you pointed out less code. As it turns out though, the find brings a lot more trouble then going the table loop. So I'll bite the bullet and do the table looping with more code. Sounds like I'll get a lot less aggravation.

Thanks,

Joe

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Feb 21, 2012 Feb 21, 2012

Copy link to clipboard

Copied

Hi Joe,

Here is some code that will find each table in the document's (doc) main text flow. For each table, it will call a processTable function (which you would define). In my post, I referred to GetTextItems, but the method is actually called GetText. Most text objects like paragraphs, flows, text frames, etc., have a GetText method.

var flow = doc.MainFlowInDoc;
var textItems = flow.GetText(Constants.FTI_TblAnchor);
for (var i = 0; i < textItems.len; i += 1) {
  tbl = doc.GetUniqueObject(Constants.FO_Tbl, textItems.obj.Unique);
  processTable(tbl, doc);
}

Rick

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Participant ,
Feb 21, 2012 Feb 21, 2012

Copy link to clipboard

Copied

Hi Rick,

I tried using your code but I am not getting the result I'd like. I want to cut the table, insert a new paragraph, and then paste the table into the new paragraph I created. I had that successfully working with the find method but it only worked on the first table found.

Using the suggested for loop, I originally couldn't get the cut to work however after doing some research I figured out the appropriate text locs and offsets that the text range needed to be in order to just cut the table. So this will actually cut the table:

   var vDoc=app.ActiveDoc;

    var vFlow = vDoc.MainFlowInDoc;

    var vTextItems = vFlow.GetText(Constants.FTI_TblAnchor);

    for (var i = 0; i < vTextItems.len; i += 1)

    {

        var vTbl = vDoc.GetUniqueObject(Constants.FO_Tbl, vTextItems.obj.Unique);

          var vTblTextRange=new TextRange ();

        vTblTextRange.beg.obj=vTbl.TextLoc.obj;

        vTblTextRange.beg.offset = vTbl.TextLoc.offset;

        vTblTextRange.end.obj=vTbl.TextLoc.obj;

        vTblTextRange.end.offset = Constants.FV_OBJ_END_OFFSET;

         vDoc.TextSelection=vTblTextRange;

        vDoc.Cut (0);

        }

However, I haven't been able to figure out how to insert a paragraph right after the paragraph that table was originally part of and then paste the table into that new paragraph.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Participant ,
Feb 21, 2012 Feb 21, 2012

Copy link to clipboard

Copied

Hi Rick,

Well, following up on the previous posting, I actually did figure out how to make it work but it seems rather inefficient. I can insert a new paragraph right after the paragraph that has the table anchor but when i cut the table, i also cut the paragraph i just created. So to get around that, I create two paragraphs, so that there will be one paragraph left after i do the cut and that is the paragraph that I paste the table into. Once the table is pasted into the new paragraph, I delete the other paragraph that I created.

Here's the updated code from the for loop:

var vTbl = vDoc.GetUniqueObject(Constants.FO_Tbl, vTextItems.obj.Unique);                 

var vAnchorPgf=vDoc.NewSeriesPgf (vTbl.TextLoc.obj)      

var vAnchorPgf2=vDoc.NewSeriesPgf (vAnchorPgf);        

var vAnchorTextLoc=new TextLoc (vAnchorPgf2, 0);             

var vTblTextRange=new TextRange ();        

vTblTextRange.beg.obj=vTbl.TextLoc.obj;       

vTblTextRange.beg.offset = vTbl.TextLoc.offset;        

vTblTextRange.end.obj=vTbl.TextLoc.obj;        

vTblTextRange.end.offset = Constants.FV_OBJ_END_OFFSET                 

vDoc.TextSelection=vTblTextRange;        

vDoc.Cut (0);                

vTblTextRange.beg.obj=vAnchorTextLoc.obj;        

vTblTextRange.beg.offset = 0;              

vTblTextRange.end.obj=vAnchorTextLoc.obj;       

vTblTextRange.end.offset =0;                 

vDoc.TextSelection=vTblTextRange;       

vDoc.Paste (0);                   

vAnchorPgf2.Delete();        

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
Oct 29, 2012 Oct 29, 2012

Copy link to clipboard

Copied

There is something I've noticed about Constants.FV_OBJ_END_OFFSET. Instead of a reasonable number, for example, 57, it seems to be a long number like 1342177280.

Is this expected? If not, could it be causing FM to crash after setting a text range?

Thanks,

Jason

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
Oct 29, 2012 Oct 29, 2012

Copy link to clipboard

Copied

LATEST

Constants.FV_OBJ_END_OFFSET is the last position of a textrange (text location).

This is expected. I used it several times in ES and FDK progamming, with no issues

Markus

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines