Skip to main content
Inspiring
June 22, 2022
Answered

Javascript to find a similar filename among all open documents?

  • June 22, 2022
  • 3 replies
  • 2203 views

Hi all,

This seems to be something I can't find an easy answer to.

I'm trying to take the filename of an active document, and use it to search through all open documents and find a close match.

For example:

Client-BDA_spec-sheet-US_v1.indd  <- if this is the active document

Client-TRA_spec-sheet-US_v2.indd

Client-BDC_spec-sheet-A4_v4.indd

Client-BDA_spec-sheet-A4_v1.indd  <- the script then finds this open document (perhaps making it active)

Client-TRA_spec-sheet-A4_v1.indd

Client-BDC_spec-sheet-US_v2.indd

 

Don't laugh but this is as far I got

var doc = app.activeDocument;
var docName = doc.name;

    function findMatch(){
	for(var i = 0; i < app.documents.length; i++){
		// I GIVE UP!!!
		}
}

 Any help is much appreciated, as always. J

This topic has been closed for replies.
Correct answer m1b

Ah I see now. It is the v1 or v2 that is a problem here. You are now saying that it's okay to match a v2 with a v1 document, so that's likely why my script didn't find it. Here's an updated version. I just added a new argument: ignoreThis, which is a regex that will be completely ignored (it'll simply be removed before the comparison) so now it'll match documents that have differing version numbers with this regex /_v\d+/ . I hope I've understood now!

- Mark

 

 

var doc = app.activeDocument,
    myA4Doc = getDocumentByNameFindChange(doc, /-US/, '-A4', /_v\d+/);

if (myA4Doc != undefined)
    app.activeDocument = myA4Doc;

/**
 * Make a document active, based on its
 * name, relative to another document.
 *
 * @9397041 {activeDoc} activeDoc - a Document
 * @9397041 {RegExp} findWhat - regex to find with
 * @9397041 {String} changeTo - text to change to
 * @9397041 {RegExp} ignoreThis - regex to ignore
 * @Returns {Document} the matched Document
 */
function getDocumentByNameFindChange(activeDoc, findWhat, changeTo, ignoreThis) {
    // store a version of the active doc's name
    // but with the replacement text
    var findThisName = activeDoc.name
        .replace(findWhat, changeTo)
        // and remove the ignored part
        .replace(ignoreThis, '');

    for (var i = 0; i < app.documents.length; i++) {
        var doc = app.documents[i];

        // don't want activeDoc
        if (doc === activeDoc)
            continue;

        // check if name matches (minus the ignored part)
        if (doc.name.replace(ignoreThis, '') == findThisName)
            return doc;
    }

    // if flow gets to here
    // no document was found
    // so return nothing
}

 

 

 


And here's another version that will toggle back and forth between A4 and US versions. You configure it with the two arrays you pass as arguments. findWhat and changeTo can be arrays in this version.

- Mark

var doc = app.activeDocument,
    myA4Doc = getDocumentByNameFindChange(doc, [/-US/, /-A4/], ['-A4', '-US'], /_v\d+/);

if (myA4Doc != undefined)
    app.activeDocument = myA4Doc;

/**
 * Make a document active, based on its
 * name, relative to another document.
 * 
 * findWhat and changeTo can be Arrays
 * such that if findWhat[i] matches active
 * document name then switch to document
 * named after doing changeTo[i].
 * @9397041 {activeDoc} activeDoc - a Document
 * @9397041 {Array[RegExp]} findWhat - regex to find with
 * @9397041 {Array[String]} changeTo - text to change to
 * @9397041 {RegExp} ignoreThis - regex to ignore
 * @Returns {Document} the matched Document
 */
function getDocumentByNameFindChange(activeDoc, findWhat, changeTo, ignoreThis) {

    var activeName = activeDoc.name,
        index = 0;

    // work out which findWhat is in document
    if (findWhat.hasOwnProperty('0')) {
        for (index = 0; index < findWhat.length; index++)
            if (findWhat[index].test(activeName))
                break;
    }

    else {
        // just put them in an array so we
        // can handle them the same later
        findWhat = [findWhat];
        changeTo = [changeTo]
    }

    // store a version of the active doc's name
    // but with the replacement text
    var findThisName = activeDoc.name
        .replace(findWhat[index], changeTo[index])
        // and remove the ignored part
        .replace(ignoreThis, '');

    for (var i = 0; i < app.documents.length; i++) {
        var doc = app.documents[i];

        // don't want activeDoc
        if (doc === activeDoc)
            continue;

        // check if name matches (minus the ignored part)
        if (doc.name.replace(ignoreThis, '') == findThisName)
            return doc;
    }

    // if flow gets to here
    // no document was found
    // so return nothing
}

3 replies

Marc Autret
Brainiac
June 23, 2022

Hi @JustyR 

 

The Levenshtein distance could provide a more 'agnostic' approach to your question. You just have to filter out the suffix

 

/_spec-sheet-[a-z0-9]+_v\d+\.indd$/i

 

before processing, as this part should be ignored by the algorithm (if I understand properly your last comment.)

 

Here is a possible implementation of the whole thing:

https://github.com/indiscripts/IdGoodies/blob/master/full/DocShowClosestByName.jsx

 

Not sure it answers your original question but it was fun to code 😉

 

Best,

Marc

JustyRAuthor
Inspiring
June 23, 2022

Hi, Marc, thanks for taking the time to write something so complete.

As you mentioned, it doesn't quite fit my needs though. It does switch docs when it finds a match but it's a bit too forgiving.

For example, if I run the script with the following four files open:

IR XRL-Spec Sheet-A4_v1.indd   <- ACTIVE document

IR XRL-Spec Sheet-US_v2.indd   <- target doc it is supposed to switch to

IR XRT-Spec Sheet-A4_v1.indd   <- but it switches to this one instead  

IR XRT-Spec Sheet-US_v1.indd 

 

It's as though the const MY_DROP_REGEX is being ignored.

J

m1b
Community Expert
June 23, 2022

Ah I see now. It is the v1 or v2 that is a problem here. You are now saying that it's okay to match a v2 with a v1 document, so that's likely why my script didn't find it. Here's an updated version. I just added a new argument: ignoreThis, which is a regex that will be completely ignored (it'll simply be removed before the comparison) so now it'll match documents that have differing version numbers with this regex /_v\d+/ . I hope I've understood now!

- Mark

 

 

var doc = app.activeDocument,
    myA4Doc = getDocumentByNameFindChange(doc, /-US/, '-A4', /_v\d+/);

if (myA4Doc != undefined)
    app.activeDocument = myA4Doc;

/**
 * Make a document active, based on its
 * name, relative to another document.
 *
 * @9397041 {activeDoc} activeDoc - a Document
 * @9397041 {RegExp} findWhat - regex to find with
 * @9397041 {String} changeTo - text to change to
 * @9397041 {RegExp} ignoreThis - regex to ignore
 * @Returns {Document} the matched Document
 */
function getDocumentByNameFindChange(activeDoc, findWhat, changeTo, ignoreThis) {
    // store a version of the active doc's name
    // but with the replacement text
    var findThisName = activeDoc.name
        .replace(findWhat, changeTo)
        // and remove the ignored part
        .replace(ignoreThis, '');

    for (var i = 0; i < app.documents.length; i++) {
        var doc = app.documents[i];

        // don't want activeDoc
        if (doc === activeDoc)
            continue;

        // check if name matches (minus the ignored part)
        if (doc.name.replace(ignoreThis, '') == findThisName)
            return doc;
    }

    // if flow gets to here
    // no document was found
    // so return nothing
}

 

 

 

JustyRAuthor
Inspiring
June 22, 2022

Had a brainwave and got it working, albeit not quite in the same way as described in my initial post.

@m1b gave me a solution to a very similar problem, which I've used to get this one working.

#target InDesign

var doc = app.activeDocument;
var docName = doc.name;
var docName = getDocumentByRegex(/-A4/g);

if (docName != undefined)
    app.activeDocument = docName;

function getDocumentByRegex(regex) {
    for (var i = 0; i < app.documents.length; i++) {
        var doc = app.documents[i];
        if (regex.test(doc.name))
            return doc;
    }
}

 

 

 

m1b
Community Expert
June 23, 2022

Hi @JustyR, I'm a little worried that the function I supplied for the other question might fail in this case. It will find the *first* document with -A4, which might not always match the client code of your current document. How about this function? Can you see what it does? Let me know if you have questions.

- Mark

 

 

var doc = app.activeDocument;
var myA4Doc = getDocumentByNameFindChange(doc, /-US/, '-A4');

if (myA4Doc != undefined)
    app.activeDocument = myA4Doc;

/**
 * Make a document active, based on its
 * name, relative to another document.
 * @param {activeDoc} activeDoc - a Document
 * @param {RegExp} findWhat - regex to find with
 * @param {String} changeTo - text to change to
 */
function getDocumentByNameFindChange(activeDoc, findWhat, changeTo) {
    // store a version of the active doc's name
    // but with the replacement text
    var findThisName = activeDoc.name.replace(findWhat, changeTo);

    for (var i = 0; i < app.documents.length; i++) {
        var doc = app.documents[i];

        // don't want activeDoc
        if (doc === activeDoc)
            continue;

        // check if name matches
        if (doc.name == findThisName)
            return doc;
    }

    // if flow gets to here
    // no document was found
    // so return nothing
}

 

 

 

JustyRAuthor
Inspiring
June 23, 2022

Sorry @JustyR, I must have misunderstood your use-case.

 

I thought you wanted to make the A4 version of the "same" active US document active. That is what your diagram says to me, so:

• if Client-BDA_spec-sheet-US_v1.indd is active then you want Client-BDA_spec-sheet-A4_v1.indd.

• if Client-BDC_spec-sheet-US_v2.indd is active then you want Client-BDC_spec-sheet-A4_v2.indd.

This is what my code does (excepting for bugs, which are likely!) when I run it. You didn't mention the v1, v2 part, which might be a consideration. At the moment it only matches with the same version number—maybe that's why it didn't work for you? I might need a better understanding of what you are trying to achieve. Oh well.

- Mark


No need to apologise. I'm indebted to you guys for helping.

I think you've understood it.

There are two versions of each document. One in A4, one in US Letter.

The naming convention is like this:

[client]-[product]-Spec Sheet-[size]_[version].indd

For example:

IR XRL-Spec Sheet-A4_v1.indd   <- If this is the ACTIVE document

IR XRL-Spec Sheet-US_v2.indd   <- the script finds this document

IR GHU2400-Spec Sheet-A4_v1.indd 

IR GHU2400-Spec Sheet-US_v1.indd 

IR Adventurer-Spec Sheet-A4_v1.indd 

IR Adventurer-Spec Sheet-US_v1.indd

 

In the example above, if stripped down, the target doc is XRL A4 and the script then finds its sibling XRL US.

Does that make sense?

J

Inspiring
June 22, 2022

Assuming that you want to match the documents for Client-BDA, you might try this after you define docName:

var clientName = docName.split("_")[0];

which will be the first piece of the name of the active document. In your loop, then, you also split the names of the other open documents to find a match. 
Not sure what you want to do if there are multiple matches, but item [1] of docName.split will be a string starting with "spec-sheet" and item [2] will be the version number. So you could use a second and third loop to check for matches in the second and third pieces of the name. 

Hope this helps,

 Bob