Skip to main content
Participant
August 15, 2019
Question

Sort alphabetically a comma separated list

  • August 15, 2019
  • 1 reply
  • 1671 views

Hello,

In my document I have lists separated by comma like this one :

Esquive, Maniement d’une arme de guerre (kukri), Attaque en finesse, Arme de prédilection (kukri)

I need to sort it alphabetically to :

Arme de prédilection (kukri), Attaque en finesse, Esquive, Maniement d’une arme de guerre (kukri)

Problem is : I don't know how to script

I know there a sort paragraph script in indesign, but currently I have to manually turn into paragraph my sentence list, then switch back after using the script, which is boring...

Help will be greatly appreciated !

Thanks

This topic has been closed for replies.

1 reply

Jongware
Community Expert
Community Expert
August 15, 2019

That would be

list = app.selection[0].contents;

list = list.split(/,\s*/);

list.sort();

list = list.join(', ');

app.selection[0].contents = list;

Select all of the text of your list and run this script. Do not select the hard return at the end, if there is one! If you do, it will get sorted along with the rest.

The magic 'split' expression uses a regular expression so zero or one or even multiple spaces after the comma can automatically be discarded.

As with one of the options in the Sort Paragraphs sample script, do not use this if you have mixed formatting in your text. You will see that the text gets replaced with the sorted list but the formatting stays in its place ... (That's, incidentally, why Sort Paragraphs has two options. This is the fast one; the "safe" option is much slower, and I cannot type it from memory either .)

KarmaromsAuthor
Participant
August 16, 2019

Thanks a lot !

As with one of the options in the Sort Paragraphs sample script, do not use this if you have mixed formatting in your text.

Unfortunately, this is what I have :/

Jongware
Community Expert
Community Expert
August 18, 2019

My 'easy' way of sorting was to use purely the textual contents of your list, that is, the contents as a plain text JavaScript string. Then this list can be split, sorted, and joined, all internally in JavaScript, and finally the characters can be written back to InDesign.

So why won't this work with the formatting included? Because this "formatting" is not part of the "textual contents" of that string, it only lives inside your InDesign document as a more (very much so) complex object. InDesign needs to know the font, size, spacing, color, styles, and so much more​ for each of the individual characters. On top of that, not all "contents" of an InDesign text object may actually be characters. End- and footnotes, index markers, those colored pop-up notes (that InDesign should have converted to PDF Sticky notes long ago), tables, inline text frames, and many more objects cannot be converted to a reasonable JavaScript plain text equivalent, and they will not get converted to plain text when read into JavaScript. That means that if you replace the original text with the sorted list, all of these items will get replaced with a placeholder character or silently disappear.

So the trick is that while you can sort the list in memory, to move the items in the actual order in the document, you must manipulate their original InDesign Text objects. Here comes the snag: I did not look in to what SortParagraphs actually does, but I imagine it's relatively easy to move paragraphs around. All (*cough* perhaps that should be "all", with scare quotes) you have to do is keep track of what needs moving where, and where everything else moves to when you did that. Kind of a Towers of Hanoi problem I suppose.

The problem is that in your case, you want to move selections of characters around inside another selection – your original selected list, remember? That gets complicated real fast. Also, when I tried exactly that, I forgot about the commas! They should be ignored when sorting, deleted from the original, then re-inserted when the strings are in the correct order again. That means you'd not only have to keep track of the string positions themselves, but also that of the commas, and when replacing, move each new list item exactly between two existing commas.

It would all still be doable but I found it much more straightforward to cheat: copy the sorted list items into a new, temporary text frame, and when done move its entire contents back to the original text.

// 1. gather the text to sort

text = app.selection[0];

// 2. split into ranges ending with a comma

list = [];

start = 0;

while (start < text.characters.length)

{

    end = text.contents.indexOf(',',start);

    if (end < 0)

        end = text.characters.length;

    list.push (text.characters.itemByRange(start,end-1));

    start = end+1;

    while (start < text.characters.length && text.characters[start].contents == ' ')

        start++;

}

// 3. sort

list.sort (function(a,b) { return String(a.contents).localeCompare(b.contents); });

// 4. create a temporary text frame and fill it

frame = app.activeDocument.textFrames.add();

for (i=0; i<list.length; i++)

{

    if (i)

    {

        frame.parentStory.texts[0].insertionPoints[-1].appliedCharacterStyle = app.activeDocument.characterStyles.item("[None]");

        frame.parentStory.texts[0].insertionPoints[-1].contents = ', ';

        frame.parentStory.texts[0].characters.itemByRange(-2,-1).clearOverrides (OverrideType.CHARACTER_ONLY);

    }

    list.duplicate (LocationOptions.AT_END, frame.parentStory.texts[0]);

}

// 5. replace original selection with temp frame text

text.remove();

frame.parentStory.texts[0].move (LocationOptions.AT_END, text);

// 6. remove further evidence of tinkering

frame.remove();

When run on a selection, this is the before-and-after result. You see the italicized "kukri" remains italicized; I imagine it's primarily this sort of formatting that you are concerned about. But also note that there is a footnote in one of the list items, and two have an Index marker; these will remain in their proper place. I did not test with other – weirder and rarerer – native InDesign objects, based on the premise that these are not likely to appear in such a short text.

(Edit: hm. See that superscript comma after "finesse²"? That's because freshly inserted plain text appears with the formatting of the character before it, just like in the interface. And a footnote usually has superscript formatting, so it uses that. The same problem will appear if the last character of a list item has some other color or font or really anything of an override. So, let's add a clearOverrrides for the comma. Next problem: a character style does not count as an explicit override! Quite the contrary, it is designed to not count as such! So set it to "[None]" before inserting the text.

There is an additional potential problem here, and I hope this does not count for your text: "clearOverrides" clears all overrides. If you are properly working with Paragraph Styles, then this is not a problem and the clear-overrides will reset formatting to your plain paragraph font and size. But if you do not use Paragraph Styles – why not? please do! – then the font for the comma will be reset to whatever you have in [Basic Paragraph]. Use styles! They are there for a reason!)