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

Javascript to find a similar filename among all open documents?

Contributor ,
Jun 22, 2022 Jun 22, 2022

Copy link to clipboard

Copied

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

TOPICS
Scripting

Views

783

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

Community Expert , Jun 23, 2022 Jun 23, 2022

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 
...

Votes

Translate

Translate
Engaged ,
Jun 22, 2022 Jun 22, 2022

Copy link to clipboard

Copied

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

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
Contributor ,
Jun 22, 2022 Jun 22, 2022

Copy link to clipboard

Copied

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;
    }
}

 

 

 

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 ,
Jun 22, 2022 Jun 22, 2022

Copy link to clipboard

Copied

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
}

 

 

 

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
Contributor ,
Jun 23, 2022 Jun 23, 2022

Copy link to clipboard

Copied

Thanks Mark. I tried it but it didn't do anything (didn't switch to a matched doc). I wonder if it needs a more robust regex or even a split, like Bob suggested. 

As shown in my first post, the first 3/4 of the filename changes but will always end with either "-US-v#.indd" or "-A4-v#.indd". So it's trying to find a match for the first part that counts, something like this regex (/(.*)(?=-US|A4)/i)

J

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 ,
Jun 23, 2022 Jun 23, 2022

Copy link to clipboard

Copied

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

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
Contributor ,
Jun 23, 2022 Jun 23, 2022

Copy link to clipboard

Copied

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

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
Contributor ,
Jun 23, 2022 Jun 23, 2022

Copy link to clipboard

Copied

Meant to say active doc not target doc. I keep rushing and making typos. Wish this forum had an edit button. 

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
Guide ,
Jun 23, 2022 Jun 23, 2022

Copy link to clipboard

Copied

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

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
Contributor ,
Jun 23, 2022 Jun 23, 2022

Copy link to clipboard

Copied

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

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 ,
Jun 23, 2022 Jun 23, 2022

Copy link to clipboard

Copied

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.
 *
 * @Param {activeDoc} activeDoc - a Document
 * @Param {RegExp} findWhat - regex to find with
 * @Param {String} changeTo - text to change to
 * @Param {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
}

 

 

 

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 ,
Jun 23, 2022 Jun 23, 2022

Copy link to clipboard

Copied

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].
 * @Param {activeDoc} activeDoc - a Document
 * @Param {Array[RegExp]} findWhat - regex to find with
 * @Param {Array[String]} changeTo - text to change to
 * @Param {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
}

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
Contributor ,
Jun 23, 2022 Jun 23, 2022

Copy link to clipboard

Copied

I tried both but neither switches to another open file. Hmmm, the plot thickens.

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
Contributor ,
Jun 23, 2022 Jun 23, 2022

Copy link to clipboard

Copied

@m1b I got your second one (the one that switches) to work for me by changing the ignore regex on line 2 to 
/-spec-sheet-.*/

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
Guide ,
Jun 23, 2022 Jun 23, 2022

Copy link to clipboard

Copied

Well it's really up to you to specify what needs to be ignored. The script can't guess your goal.

 

In terms of Levenshtein distance,

IR XRT-Spec Sheet-A4_v1.indd

is clearly closer to

IR XRL-Spec Sheet-A4_v1.indd

than

IR XRL-Spec Sheet-US_v2.indd.

 

Now if you set MY_DROP_REGEX to

/-Spec Sheet-[a-z0-9]+_v\d+\.indd$/

or even to /-.+\.indd$/

that should make a huge difference.

 

Marc

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
Contributor ,
Jun 23, 2022 Jun 23, 2022

Copy link to clipboard

Copied

I've updated the regex to /-spec-sheet-.*-[A4]_v\d+\.indd$/ which is now more accurate.

However, if a filename has something like IR CNC1-spec-sheet-A4_v1.indd, it will match with IR CNC2-spec-sheet-A4_v1.indd

How can I get the script to take account of numbers in the first part of the filename?

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 ,
Jun 23, 2022 Jun 23, 2022

Copy link to clipboard

Copied

That regex isn't right because [A4] means match any single A or 4. I also noticed that your capitalization isn't consistent so add the 'i' flag to the regex to make it case insensitive. Eg /spec-sheet-A4/i - Mark

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 ,
Jun 23, 2022 Jun 23, 2022

Copy link to clipboard

Copied

LATEST

BTW, It would save some time if you sent us a listing of all your *actual* file names. At the moment what you are saying doesn't match with the results you're getting. Also the regex you posted last doesn't make sense. The one I posted with my last script should work if you add the i flag to each regex. We'll get there!

- Mark

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