[AI CC-CC2022] /[CC2015] RegExp поиск/замена с сохранением форматирования

Статус
Закрыто для дальнейших ответов.

dumbm1

Топикстартер
12 лет на форуме
Сообщения
423
Реакции
197
Можно ли с помощью ExtendScript RegExp произвести глобальную замену в текстовом блоке с сохранением исходного форматирования?

Попробовал разные варианты - пока что 'otbline'

Поиск/замена в:
  • TextFrame.Words ограничивается одним символом
  • TextFrame.TextRanges.contents ограничивается одним словом
  • TextFrame.Lines приводит форматирование всех символов строки к формату первого символа строки
  • TextFrame (TextFrame.TextRange) - то же самое, только для всего блока (фрейма) текста + сбрасывает в дефолт форматирования всех абзацев блока

Пример (плохой):
Код:
var reg = /a/gmi;
var replacer = '*';
var fr = activeDocument.textFrames[0];
fr.contents = fr.contents.replace (reg , replacer);

PS. Поиск/замена в InDesign, MSWord и т.д. не обсуждаются - там всё отлично ;)
 
ну, как... по сути нужно сохранить параметры оформления текста, провести замены в text range (или в нескольких, если различиями можно пренебречь), и применить к нему обратно это оформление
долго и нудно. параметров оформления там 100500
 
  • Спасибо
Реакции: dumbm1
или как-то разбить текст на куски с одинаковым форматированием и искать/менять по очереди в каждом куске
 
text ranges это и есть куски с одинаковым форматированием. я так понял, что все равно не получается в них просто менять.
 
а когда перебираешь в цикле, то каждый
Код:
TextRanges[i]
- это один отдельный символ
 
Последнее редактирование:
может они разные все? ) символы это characters вообще говоря, text ranges - куски с одинаковым оформлением. но там отличаться может что угодно, лигатуры какие-нибудь включены/выключены - и это будет уже другой text range
 
Все это, конечно очень печально, хоть и ожидаемо.
Но, как обычно, есть и извращенные обходные варианты, например
upload_2016-8-5_9-37-18.png
 
  • Спасибо
Реакции: dumbm1
может они разные все?
создаю area text или point text и печатаю любой текст...
Код:
alert(activeDocument.textFrames[0].textRanges.length);
выдаёт чётко количество напечатанных символов (включая пробелы, переводы строки и т.п.)
есть и извращенные обходные варианты, например
а можно чуть подробнее, что-то до меня пока не дошло )
 
Там регулярные выражения, по моему, не поддерживаются, а весь смысл в них.
 
Там регулярные выражения, по моему, не поддерживаются, а весь смысл в них.
Более того - поиск ведется по всему документу а не по указанным фреймам
Печальбеда 'hz'
 
А простой способ перекинуть текст Illustrator>>InDesign>>Illustrator есть?
Т.е. воспользоваться богатым функционалом поиска/замены InDesign из Illustrator.
Я очень сомневаюсь, что это хорошая идея
 
с textRanges очень странно, мне всегда казалось что они эквивалентны textStyleRange в InD
видимо, заблуждался. не очень понятно какой в них вообще тогда смысл
 
Вот это постепенно разбивает выделенный фрейм на блоки с одинаковым форматированием и производит поиск/замену в этих блоках. "Одинаковое форматирование" проверяется по 4-м параметрам (family, size, style, color). Границы между блоками из поиска выпадают. Всё это происходит посимвольно и медленно.
Код:
  function repl (reStr, replacer) {
    var re  = new RegExp (reStr, 'gmi');
    var frm = selection[0];
    var a, b,
        i   = 0,
        txtOrig, txtModif;

    frm.textRange.characters[i].select ();

    for (; ; i++) {
      try {
        a = frm.textRange.characters[i];
        b = frm.textRange.characters[i + 1];
      } catch (e) {
        _replRng ();
        break;
      }

      if (_cmprTxtAttr (a, b)) {
        b.select (true);
        continue;
      } else {
        _replRng ();
        i += txtModif.length - txtOrig.length;
        frm.textRange.characters[i + 1].select ();
        continue;
      }
    }

    function _replRng () { // nothing return; only modify global vars
      if (frm.textSelection.length > 1) {
        txtOrig                       = frm.textSelection[0].contents + frm.textSelection[1].contents;
        txtModif                      = txtOrig.replace (re, replacer);
        frm.textSelection[1].contents = txtModif.slice (-1);
        frm.textSelection[0].contents = txtModif.slice (0, -1);
      } else {
        txtOrig                       = frm.textSelection[0].contents;
        txtModif                      = txtOrig.replace (re, replacer);
        frm.textSelection[0].contents = txtModif;
      }
    }

    function _cmprTxtAttr (a, b) {
      return __compareFill (a, b) && __compareFont (a, b);

      function __compareFill (a, b) {
        var aCol = a.characterAttributes.fillColor;
        var bCol = b.characterAttributes.fillColor;

        if (aCol.typename != bCol.typename) return false;

        if (aCol.typename == 'RGBColor') {
          if (aCol.red != bCol.red || aCol.green != bCol.green || aCol.blue != bCol.blue) {
            return false;
          }
        } else if (aCol.typename == 'CMYKColor') {
          if (aCol.cyan != bCol.cyan || aCol.magenta != bCol.magenta ||
            aCol.yellow != bCol.yellow || aCol.black != bCol.black) {
            return false;
          }
        }
        return true;
      }

      function __compareFont (a, b) {
        var aFnt = a.characterAttributes;
        var bFnt = b.characterAttributes;

        if (aFnt.size != bFnt.size) return false;
        if (aFnt.textFont.style != bFnt.textFont.style) return false;
        if (aFnt.textFont.family != bFnt.textFont.family) return false;

        return true;
      }
    }
  }
 
Гм, а я так сперва понял, что основная сложность - искать во всем блоке фрагменты, частично отформатированные разным образом. А при таком подходе они и не ищутся вовсе. Так тогда действительно проще и быстрее сохранять форматирование, искать/заменять и снова применять. Другое дело, что в общем случае задача нетривиальна, ибо после замены текст может кардинально от исходного отличаться.
 
  • Спасибо
Реакции: Flame
Кстати, если паттерн попадает на текст с разным форматированием, то и в MSWord и в InDesign форматирование приводится к какому-то одному - либо по первому либо по последнему символу (кажется так, но может быть там всё немного сложнее).
Попробую ещё сделать по такому алгоритму:
  • найти совпадение
  • взять формат первого символа из совпадения
  • сделать замену
  • отформатировать по ранее взятому формату
  • и т.д.
 
Теперь в целом работает как мне надо:
Код:
function replaceKeepFormatting (reg, replacer, txtFrame) {
  var result;

  while (result = reg.exec (txtFrame.contents)) {
    for (var i = 0; i < result[0].length; i++) {
      txtFrame.characters[result.index + i].select (true);
    }
    if (txtFrame.textSelection.length == 2) {
      var str                            = (txtFrame.textSelection[0].contents + txtFrame.textSelection[1].contents).replace (reg, replacer)
      txtFrame.textSelection[1].contents = str.slice (-1);
      txtFrame.textSelection[0].contents = str.slice (0, -1);
    } else {
      txtFrame.textSelection[0].contents = (txtFrame.textSelection[0].contents).replace (reg, replacer);
    }
    result.lastIndex += replacer.length - result[0].length;
    txtFrame.textRange.deSelect ();
  }
}
 
Последнее редактирование:
  • Спасибо
Реакции: Skvoznyak
нормально, может еще попробовать без цикла сразу этот несчастный textrange нужной длины выделять?
 
ещё покороче вариант
Код:
  /**
   * change contents of word or string remain formatting
   * autor (c)pixxxel schubser
   * */
  function repl (reg, replacer) {
     var txtFrame = selection[0],
        result;

    while (result = reg.exec (txtFrame.contents)) {
      try {
        var aCon      = txtFrame.characters[result.index];
        aCon.length   = result[0].length;
        aCon.contents = aCon.contents.replace (reg, replacer);
      } catch (e) {
      }
    }
  }
 
  • Спасибо
Реакции: Flame
Статус
Закрыто для дальнейших ответов.