[JS] Problem with change grep with look behind/ahead and /K

Guru ,
Mar 16, 2022 Mar 16, 2022

Copy link to clipboard

Copied

Dear forum,

I encountered this problem while writing a complex script that imitates the find-change dialog. Its purpose is to find RegExes at the beginning and/or end of lines (which InDesign doesn’t allow).

 Let’s illustrate my issue with an example. (I attached a test document below).

I simplified things to make my question as clear as possible.

 First, I set find what to ra\> (ra at the end of a word) and change format to, say, blue color.

 KasyanServetsky_0-1647439793087.png

And run this script:

main();

function main() {
	var txt, changed,
	doc = app.activeDocument,
	found = doc.findGrep(false);
	
	for (var i = 0; i < found.length; i++) {
		txt = found[i];
		changed = txt.changeGrep();
		$.writeln( i + " - " + changed.length);
	}
}

It works as expected: all 6 found items are changed one by one:

 KasyanServetsky_2-1647439879420.png

Now let’s change find what to a regex with look behind: (?<=illo)ra

 KasyanServetsky_3-1647439903131.png

And run the script again. As before, 6 items were found, but were not changed:

KasyanServetsky_4-1647439939397.png

When I change it manually in InDesign one by one, it works.

The same happens with regexes using look ahead and /K, for example:

  • illo(?=ra)
  • illo\Kra

Any ideas why this happens?

TOPICS
Scripting

Views

403

Likes

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 2 Correct answers

Guru , Mar 17, 2022 Mar 17, 2022
Thanks for your replies, Uwe and Brian!It seems I found a workaround: reapply findWhat to the found text and after that apply change:main(); function main() { var txt, changed, doc = app.activeDocument, found = doc.findGrep(false); for (var i = 0; i < found.length; i++) { txt = found[i]; app.findGrepPreferences.findWhat = txt.contents; changed = txt.changeGrep(); $.writeln( i + " - " + changed.length); } }

Likes

Translate

Translate
Guide , Mar 17, 2022 Mar 17, 2022
Hi Kasyan,
Any ideas why this happens?
If you analyze your procedure more closely you'll realize this is not a bug. Indeed, each found Text considered separately no longer satisfies the lookbehind assertion! So your command changed=txt.changeGrep(); has no effect. Take a look at the following example: The GREP I use here is `(?<=e)qu.` so it captures every `qu.` pattern iff it is prefixed by 'e'. The frame above shows the final result of Find/Change executed from InDesign—the qui, quo, qua match...

Likes

Translate

Translate
Advocate ,
Mar 16, 2022 Mar 16, 2022

Copy link to clipboard

Copied

Take a look at this reply here:
https://community.adobe.com/t5/indesign-discussions/positive-lookahead-not-working/m-p/8730391#M3217...

Marc also wrote this: GREP ≠ ExtendScript RegExp ≄ JavaScript RegExp

Likes

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
Guru ,
Mar 16, 2022 Mar 16, 2022

Copy link to clipboard

Copied

Thanks, Jean-Claude! I will study this post.

Likes

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
Adobe Community Professional ,
Mar 16, 2022 Mar 16, 2022

Copy link to clipboard

Copied

Hi Jean-Claude,

but in Kasyan's sample we do not deal with ExtendScript's RegExp or JavaScript RegExp.

It's the GREP implementation with InDesign's ExtendScript.

 

Tested Kasyan's case and I see the same issue with my German InDesign 2022 on Windows 10.

 

The thing that does work is, change all found instances in one go:

 

app.documents[0].changeGrep();

 

 

But perhaps that's not the thing Kasyan is after ?!

 

Regards,
Uwe Laubender

( ACP )

Likes

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
Adobe Community Professional ,
Mar 16, 2022 Mar 16, 2022

Copy link to clipboard

Copied

I think it has something to do with how the value of the Text for your find is only ra, but changeGrep is probably still trying to execute a change based on a findWhat with the lookbehind. That's why doc.changeGrep() works, but changeGrep() on a Text object of only "ra" would not. A workaround would be to take the Text object and manually apply the change features to it. Basically, I think .changeGrep() still executes its own .findGrep() on the object it's being called on, if that makes sense. It kind of has to, since you can call .changeGrep() without calling .findGrep() first. 

Likes

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
Guru ,
Mar 17, 2022 Mar 17, 2022

Copy link to clipboard

Copied

Thanks for your replies, Uwe and Brian!

It seems I found a workaround: reapply findWhat to the found text and after that apply change:

main();

function main() {
	var txt, changed,
	doc = app.activeDocument,
	found = doc.findGrep(false);
	
	for (var i = 0; i < found.length; i++) {
		txt = found[i];
		app.findGrepPreferences.findWhat = txt.contents;
		changed = txt.changeGrep();
		$.writeln( i + " - " + changed.length);
	}
}

 

Likes

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
Adobe Community Professional ,
Mar 17, 2022 Mar 17, 2022

Copy link to clipboard

Copied

Good solution!

Likes

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
Adobe Community Professional ,
Mar 17, 2022 Mar 17, 2022

Copy link to clipboard

Copied

Hi Brian,

interesting deliberations.

Of course we can do the following to check if the found first word of a found text is at the beginning of a line of text:

 

main();

function main()
{
	
	var txt, changed,
	doc = app.activeDocument,
	found = doc.findGrep(false);

	for (var i = 0; i < found.length; i++)
	{
		if( found[i].words[0] == found[i].lines[0].words[0] )
		{
			$.writeln( i +" - "+ found[i].words[0].contents );
		}
	}
}

 

 

But what next?

And here I'm not sure what the user's expectation is for Kasyan's main script:

Should the change be applied as the user has defined it in the GREP Find/Change GUI of InDesign?

 

How would you do this now when found[i].changeGrep() fails?

Should we go to app.changeGrepPreferences.properties and check every value and then apply it to the found text?

 

Regards,
Uwe Laubender

( ACP )

 

//EDITED

Likes

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
Guide ,
Mar 17, 2022 Mar 17, 2022

Copy link to clipboard

Copied

Hi Kasyan,

 

quote

Any ideas why this happens?


If you analyze your procedure more closely you'll realize this is not a bug. Indeed, each found Text considered separately no longer satisfies the lookbehind assertion! So your command changed=txt.changeGrep(); has no effect.

 

Take a look at the following example:

 

found-strings.png

The GREP I use here is `(?<=e)qu.` so it captures every `qu.` pattern iff it is prefixed by 'e'. The frame above shows the final result of Find/Change executed from InDesign—the qui, quo, qua matching texts are styled in blue.

 

Now, what are the Text strings resulting from doc.findGrep(false)? The alert box shows them, based on:

 

(function(  doc,found,i,txt,changed)
{
    doc = app.properties.activeDocument;
    found = doc.findGrep(false);
    
    /*
    for( var i = 0; i < found.length; i++ )
    {
        txt = found[i];
        changed = txt.changeGrep();
        $.writeln( i + " - " + changed.length);
    }
    */

    // Display the `found` strings.
    // ---
    for
    (
        i=found.length ;
        i-- ;
        found[i]=found[i].texts[0].contents
    );
    alert( found.join('\r') );
})();

 

You can see that each found[i] as such—namely “qui”, “quo”, “qua”—is not preceded by 'e'. This explains why found[i].changeGrep() has no effect.

 

Hope that helps.

Marc

Likes

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
Guru ,
Apr 06, 2022 Apr 06, 2022

Copy link to clipboard

Copied

Hi Marc,

Thank you very much for your explanation! Now it's clear to me.

Sorry for my late reply! I just saw your answer.

Likes

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
Guru ,
Apr 07, 2022 Apr 07, 2022

Copy link to clipboard

Copied

LATEST

Forgot to mention: I've already published the first version of the script I mentioned in the original post and continue working on it.

Likes

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