6 Replies Latest reply on Jul 30, 2010 1:23 PM by [Jongware]

    Find text using GREP query, delete text frame

    Rand0mUser Level 1
      Beginner attempt

      (please do not give a straight answer… I'd like guidance to learn as I go)

       

      I have a saved GREP query.

       

      Goal: The script needs to use it to delete the containing text frames from every matching find.

       

      Steps:

      - from within the active document

      - call the GREP query

      - on the instance of a match, select its text frame (parentStory?)

      - delete the text frame

      - loop the steps until there are no more matches

       

      Something like that. Well then, looking at the ungroup script, I shall begin…

       

      function findDelete () {

           if (app.documents.length == 0) {

                alert ("Please have an 'Indesign' document before running this script.");

                return;

           }

           while (

       

      I'm pretty sure there's a while loop, but I don't know how to call the GREP query

       

      P.S. what's the difference between break; and return; ?

        • 1. Re: Find text using GREP query, delete text frame
          Creaticious

          Hi,

           

          thats quiet simple:, setup your Grep, iterate through all TextFrames, search for the grep and

          delte when found:

           

           

          app.findGrepPreferences = NothingEnum.nothing;

          app.changeGrepPreferences = NothingEnum.nothing;

          app.findGrepPreferences.findWhat = "my+.+grep"; // << Edit your GREP here

           

          with(app.activeDocument) {


               for(Counter = 0; Counter < textFrames.length; Counter++) {

           


                     var MyResult = textFrames.item(Counter).findGrep();

           

                              if (MyResult.length == 0) {

                            textFrames.item(Counter).remove();

                     }

               }

          }

          • 2. Re: Find text using GREP query, delete text frame
            Peter Kahrel Adobe Community Professional & MVP

            To use a GREP query in a script, look for a method loadFindChangeQuery ( )

            Execute that query, e.g. like this:

             

            var found = app.activeDocument.findGrep (true);

             

            found is returned as an array, which is empty when nothing was found. "True" returns the array in reverse order; see below.

             

            Each entry's parent text frame is this:

             

            found[i].parentTextFrames[0]

             

            Since you're going to delete things, you have to start processing your found items from back to front, which is why we wanted the found array to be returned reversed. Now you do something like this:

             

            for (i = 0; i found.length; i++)
               found[i].parentTextFrames[0].remove ();

             

            But you'll find that that's not going to work. There are two ways to get around this -- over to you!

             

            As to the difference between break and return: when used in a function, return breaks out of that function. Break breaks out only from a loop, for example. Take these two loops:

             

            function a ()

               {

               for (i = 0; i < 10; i++)

                  {

                  if (i == 3)

                      return;

                  }

               $.writeln ("Qwerty")

               }

             

             

            function a ()

               {

               for (i = 0; i < 10; i++)

                  {

                  if (i == 3)

                      break;

                  }

               $.writeln ("Qwerty")

               }

             

            Function b prints "Qwerty" in the console when i equals 3, function a does not.

             

             

            Peter

            • 3. Re: Find text using GREP query, delete text frame
              Peter Kahrel Adobe Community Professional & MVP

              Creaticious,

               

              You beat me to it with an interesting approach. But you need to traverse the text frames from back to front:

               

              for(Counter = textFrames.length-1; Counter >= 0; Counter--)

              • 4. Re: Find text using GREP query, delete text frame
                Rand0mUser Level 1

                Peter, I'm completely lost… I think I need to read up on basic JavaScript… ugh!

                 

                Please correct me if I'm wrong…

                 

                Looking at what Creaticious wrote, I assume that preferences have to be changed at the beginning of the script.

                 

                app.findGrepPreferences = NothingEnum.nothing;

                app.changeGrepPreferences = NothingEnum.nothing;

                app.findGrepPreferences.findWhat = ""; // << Edit your GREP here

                 

                 

                "True" returns the array in reverse order

                 

                So, the for loop has to use the array result (True) from the findGrep method until the result is nothing found and it does so starting from the end of the document, going backwards to the beginning of the document.

                 

                for (i=0  //starts at zero. what exactly does this mean? This first instance of the found variable?

                i < found.length  //where i stops. Do the search so long as i is less than the length of the array?

                i--  // each time the search goes around the loop, decrement the value of i

                 

                 

                found[i].parentTextFrames[0]

                 

                found[i] i is variable result from the for loop gets inserted here. The result is the grep find from the end of the document to the beginning.]

                .parentTextFrames[0] selects the text frame of each found.

                 

                found[i].parentTextFrames[0].remove (); remove() is a method to remove the text frame?

                • 5. Re: Find text using GREP query, delete text frame
                  Peter Kahrel Adobe Community Professional & MVP

                  > I'm completely lost…

                   

                  Well, you asked for pointers only.

                   

                  > I think I need to read up on basic JavaScript…

                   

                  That is probably a good idea. So rather than organising a course on this forum (which is not what the forum is for), go read something on InDesign's object model and a basic introduction to JavaScript. http://oreilly.com/catalog/9780596802523/ is a start.

                   

                  >ugh!

                   

                  Not at all! It's good fun!

                   

                  Peter

                  1 person found this helpful
                  • 6. Re: Find text using GREP query, delete text frame
                    [Jongware] Most Valuable Participant

                    Pending your reading of Peter's Javascript recommendation, a few notes on your notes

                     

                    "True" returns the array in reverse order

                     

                    That means that by default the "found items" array is in logical order (first occurrence to last), but this parameter asks InDesign to return the array in reverse. If you were searching for one digit, which occur in logical order in your document, the regular "findGrep" command would return [ "1", "2", "3", "4", "5" ] but with the find-in-reverse parameter set to true, the command returns [ "5", "4", "3", "2", "1" ].

                     

                    So, the for loop has to use the array result (True) from the findGrep method until the result is nothing found and it does so starting from the end of the document, going backwards to the beginning of the document.

                     

                    Y.. n.. what has the true to do with this? It's just a parameter to findGrep. "After" the command has been executed, it no longer does something else. As above, it's the result of the findGrep command that is returned in reverse.

                    This is, by the way, why you need a basic Javascript fresh-up

                     

                    Now, if I disregard your last comment, we've gone back to what findGrep returns: an array. An array is a list, no more, no less. What -- "A list of what?", you ask? The all-encompassing answer is "Anything you want!". You can put just about everything into an array, and InDesign can do that as well.

                    However: for most commands it is specified what is 'contained' in the returned array. In the case of findGrep, it is a list of Text Objects that point immediately to the original text in InDesign. It Points To -- This Is Important. I'll tell you in a minute why.

                     

                    Going back to the 'array' datatype. Since this is a simple list, it has a length; just like your groceries' list. Its length is important too, because it can tell you things about the findGrep command you just executed. For example, what if the length of the found array is 0 (zero) ... Simple: the search text was not found. If the length of the list is 1, the text only was found once, and if it's 12,445,678 items long, you probably found more than you asked for and you should check your 'find what' expression ...

                     

                    So at this point we have a list of items [ found text #0, found text #1, ... found text #(n-1) ] -- with in total n items and starting at 0 because that's how Javascript works (in a list of 10 items, they are numbered 0 to 9 -- in case of doubt, count on your fingers).

                     

                    We need to 'go over' each of the found items and process them, but what if your 'process' changes one of them -- for example, what if you delete the first 'found' item? That's why it is important to know that, in the case of Found Text, you get items that point to text. It means that

                     

                    1. If you change something "in" the found item array -- say, you set the font of 'found item #1' to Bold, this changes your document immediately. The Found Array = The Text In The Document. So if you delete the found item text #1 in the array, it will be deleted from the document.

                     

                    2. The Point To mechanism works against you if you change the number of characters in your document! You can consider the Point To mechanism as a sort of index into the actual document, where item #0 is "at position 123", and item #1 is "at position 245". If you delete one single character at position 124, the first item (that is, #0) will still point to what you would expect -- the first occurrence of the found text. However, the second item will still point to the original position, but the text there has been changed! (That needs another exclamation point!)

                     

                    This is why you would need the 'found' array to be in reverse order. If you change text, using the found text array, every item in the array "after" the one you change will be invalidated -- but, since you already 'processed' the ones "after" the one you are changing it's suddenly no problem. The items "after" the current one in the array occur before the ones you already processed, because the array is reversed.

                     

                    You might want to read that twice.

                     

                    Since that was a long story (a necessary one, because it's not typical Javascript behavior but highly specific to InDesign), I'll have to pass on the for syntax. I'm sorry to say you made comprehension errors in two out of three comments ... But for this basic Javascript command, you are better off starting from scratch.

                     

                    for (i=0  //starts at zero. what exactly does this mean? This first instance of the found variable?

                    i < found.length  //where i stops. Do the search so long as i is less than the length of the array?

                    i--  // each time the search goes around the loop, decrement the value of i