Skip to main content
Divya DR
Participant
April 25, 2026
Question

Find Junk characters in Indesign, without using Glyphs

  • April 25, 2026
  • 4 replies
  • 75 views

I am working on a task to find junk characters in InDesign without using Glyphs, because I already tried using Glyphs in InDesign JavaScript and it takes too much time. What are the other possible ways to find junk characters?

    4 replies

    David W. Goodrich
    Participating Frequently
    April 27, 2026

    A full discussion of missing glyphs in InDesign must include Peter Kahrel's (link removed by moderator), itself the result of extensive discussions in the old forums. In my work, the AWOL items generally are not junk, but obscure forms: rare Chinese chars., diacritics for romanizing Sanskrit, IPA, etc.  The script takes time to run because it examines every char., which is what I usually need.

    Community Expert
    April 27, 2026

    The red “tofu” box you’re seeing isn’t actually a specific character you can target with GREP it’s a missing glyph (the font can’t display that character).

    That’s why your GREP is catching lots of “junk” but not specifically those boxes. GREP works on the character itself, not how it renders.

    If you want to find those tofu boxes specifically, the most reliable way in InDesign is:

    Use Preflight > enable “Missing Glyphs”
    That will flag exactly those characters

     

    If you still want a GREP approach, the closest you can do is narrow things down with something like

    [^\x00-\x7F]

    but that will also catch valid characters like accents, dashes, etc., so it’s more of a broad sweep than a precise solution.

    If you need automation, a script is the only way to properly isolate missing glyphs, because it can check whether the font actually supports the character.

    So in short:

    GREP = good for general cleanup
    Preflight = best for tofu/missing glyphs
    Script = best if you want to automate it

     

    Script idea would be something like 
     

    var doc = app.activeDocument;

    // --- Create highlight color ---
    var color;
    try {
    color = doc.colors.itemByName("TofuHighlight");
    color.name;
    } catch(e) {
    color = doc.colors.add({
    name: "TofuHighlight",
    model: ColorModel.PROCESS,
    space: ColorSpace.RGB,
    colorValue: [255, 0, 0]
    });
    }

    // --- Create character style ---
    var style;
    try {
    style = doc.characterStyles.itemByName("TofuStyle");
    style.name;
    } catch(e) {
    style = doc.characterStyles.add({
    name: "TofuStyle",
    fillColor: color
    });
    }

    // --- Loop through characters ---
    var chars = doc.stories.everyItem().characters;

    for (var i = 0; i < chars.length; i++) {
    var ch = chars[i];

    try {
    // Missing glyphs often return glyph ID = 0
    if (ch.glyphID === 0 && ch.contents !== " ") {
    ch.appliedCharacterStyle = style;
    }
    } catch(e) {}
    }

    alert("Tofu (missing glyphs) highlighted.");

     

    At the end - you can then search for the colour in the document using the Edit>Find Change to see if there’s any remnants. 

    Between the script and the Preflight it should catch them all 

    Only this line does anything

    ch.appliedCharacterStyle = style;

    You can do other things with this line

    Replace with a placeholder - I used a question mark - but you don’t have to you can use anything

    ch.contents = "?";

    Or if you want to remove them

    ch.remove();

     

    Community Expert
    April 27, 2026

    Oh you probably want to loop backwards to avoid missing any glyphs or skipping any

     

    var doc = app.activeDocument;

    // Get all characters
    var chars = doc.stories.everyItem().characters;

    // Loop backwards
    for (var i = chars.length - 1; i >= 0; i--) {
    var ch = chars[i];

    try {
    // Detect missing glyph (tofu)
    if (ch.glyphID === 0 && ch.contents !== " ") {

    // --- ACTION ---

    // Option 1: DELETE
    ch.remove();

    // Option 2: REPLACE (use instead of remove)
    // ch.contents = "?";

    // Option 3: HIGHLIGHT (non-destructive)
    // ch.appliedCharacterStyle = style;

    }

    } catch(e) {}
    }

    alert("Done.");

     

    Divya DR
    Divya DRAuthor
    Participant
    April 27, 2026

    It works, but my requirment is to take only the tofu square, but it  highlight all the junk char can you gimme to find these type of junk. 

     

    Community Expert
    April 25, 2026

    Depends what you want to do 

     

    First thing I think of here is the Preflight - and to check for Missing Glyphs - that would pretty much do it. 

     

    You mentioned scripting, but not what you’ve tried or what isn’t working or why it’s not working - or even what you want it to do.

     

    Something like this would highlight them in red

    Then you can use Find/Replace to find the colour and decide what you want to do

    var doc = app.activeDocument;

    // --- Create / get highlight color ---
    var highlightColor;
    try {
    highlightColor = doc.colors.itemByName("JunkHighlight");
    highlightColor.name; // forces error if not valid
    } catch(e) {
    highlightColor = doc.colors.add({
    name: "JunkHighlight",
    model: ColorModel.PROCESS,
    space: ColorSpace.RGB,
    colorValue: [255, 0, 0] // bright red
    });
    }

    // --- Create / get character style ---
    var highlightStyle;
    try {
    highlightStyle = doc.characterStyles.itemByName("JunkCharStyle");
    highlightStyle.name;
    } catch(e) {
    highlightStyle = doc.characterStyles.add({
    name: "JunkCharStyle",
    fillColor: highlightColor
    });
    }

    // --- Loop through characters ---
    var chars = doc.stories.everyItem().characters;

    for (var i = 0; i < chars.length; i++) {
    var c = chars[i].contents;

    if (c.charCodeAt(0) > 127) {
    chars[i].appliedCharacterStyle = highlightStyle;
    }
    }

     

    Similarly you could write a log to the desktop - but it has limitations at the moment but could be useful

    var doc = app.activeDocument;

    // Output file on Desktop
    var file = new File(Folder.desktop + "/InDesign_Junk_Report.txt");
    file.open("w");
    file.writeln("Junk Character Report\n");

    // Get all characters
    var chars = doc.stories.everyItem().characters;

    for (var i = 0; i < chars.length; i++) {
    var ch = chars[i];
    var c = ch.contents;

    if (c && c.length > 0 && c.charCodeAt(0) > 127) {

    var code = c.charCodeAt(0);

    // Page number
    var page = "Unknown";
    try {
    page = ch.parentTextFrames[0].parentPage.name;
    } catch(e) {}

    // Line number
    var line = "Unknown";
    try {
    line = ch.lines[0].index + 1;
    } catch(e) {}

    // Context (a few characters around it)
    var context = "";
    try {
    var start = Math.max(0, i - 5);
    var end = Math.min(chars.length - 1, i + 5);
    for (var j = start; j <= end; j++) {
    context += chars[j].contents;
    }
    } catch(e) {}

    file.writeln(
    "Char: [" + c + "] " +
    "Code: " + code +
    " | Page: " + page +
    " | Line: " + line +
    " | Context: " + context
    );
    }
    }

    file.close();

    alert("Report saved to Desktop.");

     

    Or another approach would be with GREP
     

    ~S|~s|~m|\x{200B}|\x{200C}|\x{200D}|\x{FEFF}

     

    Or likes of

    [^A-Za-z0-9.,;:!?'"()\-\s]

     

    Or add other symbols you don’t want flagged
     

    [^A-Za-z0-9.,;:!?'"()\-\s+\-×÷=]