20090929

Нормализация текста в Indesign CS4

С переходом c Adobe Indesign CS2 на CS4 убедился что большинство старых скриптов отказываются работать.
Ручками правки вносить — нудно, поэтому решился-таки, переписал основные скрипты.
На удивление, всё прошло гладко, хотя программисты из Adobe отказались выпускать официальное описание скриптового движка ссылаясь на то, что мол всё можно посмотреть в редакторе ExtendendScript Toolkit.
Не беда.

Теперь я написал kstCleanUp.jsx — скрипт выполняющий чистку текстовых блоков от хлама и преведение их к типографским нормам. На данный момент полностью готов обработчик, и частично строки автозамены.



Основной скрипт kstCleanUp.jsx
Должен находиться в папке
~\AppData\Roaming\Adobe\InDesign\Version 6.0\en_GB\Scripts\Scripts Panel

 
  1: /*    Cs4Grep changer v 0.02
  2:  Скрипт выполняющий чистку текстовых блоков от хлама и преведение их к типографским нормам.
  3:  
  4:  Eugeny Borisov, 2009. flekst@gmail.com
  5: 
  6: */
  7: try {  // global handler
  8: 
  9: 
 10: // объект-заглушка для сообщений
 11: var msg_err = {
 12:  CantOpenDocument : "Откройте публикацию и повторите попытку.",
 13:  MissingChangesListFile : "Невозможно открыть файл поиска-замен",
 14:  NothingToDoChangesFile: "Файл поиска-замен пуст. Работа не имеет смысла",
 15:  UnsupportedObject: "Выделенный объект неподдерживается\nObjectType = ",
 16:  WrongFind_changeString : "Ошибка в файле параметров поиска-замены",
 17: FileLine : "Строка №: ",
 18: LineContent: "Содержимое строки: "
 19: 
 20: };
 21: /* 
 22:  файл поиска-замены 
 23:  */
 24: var changeListName = app.scriptPreferences.scriptsFolder+"/kst_changeGreep.txt";
 25: /* 
 26:  массив в который ссыпятся параметры поиска-замены 
 27:  в виде массивов  [find, change] 
 28:  где find и change имеют вид:
 29:  [0] - what/to
 30:  [1] - код для eval в контексте find/changeGrepPreferences соответственно
 31:  Засылается в функцию FillFindChangeFromArray();
 32:  */
 33: var changeList = Array(); 
 34: 
 35: 
 36: /*
 37:   Заполняет findGrepPreferences и changeGrepPreferences
 38:   из массива v.
 39:   Структура массива v описана в глобальном массиве changeList
 40: */
 41: function FillFindChangeFromArray(v) {
 42:  var find = v[0][0];
 43:  var findParams = v[0][1];
 44:  var change=v[1][0];
 45:  var changeParams = v[1][1];
 46:  app.findGrepPreferences =  NothingEnum.nothing;
 47:  with (app.findGrepPreferences) {
 48:   findWhat = find;
 49:   eval(findParams); // вот именно так и внедряются параметры
 50:  }
 51:      app.changeGrepPreferences =  NothingEnum.nothing;
 52:   with (app.changeGrepPreferences) {
 53:   changeTo = change;
 54:   eval(changeParams); // вот именно так и внедряются параметры
 55:  } 
 56: }
 57: 
 58: function PrepareChangeList() {
 59:  var changeListFile = File (changeListName);
 60:  if ( changeListFile.open("r", undefined, undefined) != true ) {
 61:   alert(msg_err.MissingChangesListFile+"\n"+changeListName);
 62:  exit();
 63:  };
 64: 
 65:  var FileData = changeListFile.read();
 66:  FileData = FileData.split("\n");
 67:  var FileStringsCount = FileData.length;
 68:  changeListFile.close();
 69:  
 70:  var i=0;
 71: 
 72:  // собираю массив замен.
 73: 
 74:  for (;i<FileStringsCount;i++) {
 75:   tmp = FileData[i];
 76:   // пропуск комментариев и пустых строк.
 77:   // по скольку предполагается замена его-то на что-то, то три символа - минималка
 78:   if ( (tmp.indexOf("#") == 0) || (tmp.length < 3)) {
 79:     continue;  
 80:   }
 81: 
 82: /* парсинг строки из файла поиски-замены
 83:  на этом этапе достоверно известно что:
 84:  -- строка -- не комментарий
 85:  -- строка не пустая
 86:  */
 87: 
 88: /*
 89:  Разделяю входную строку на параметры, 
 90:  и подготавливаю строку вывода ошибки (всякое бывает).
 91:  */
 92:     var src=tmp;
 93:  tmp = tmp.split("#");
 94:  
 95:  var errString = msg_err.WrongFind_changeString +".\n"
 96:      +  msg_err.FileLine +i+ ".\n"
 97:      +  msg_err.LineContent + src;
 98: 
 99: /*
100:  Контролируемый блок. В случае ошибки произойдет ее отлов
101:  и вывод сообщения пользователю
102:  */
103: try {
104:  var find = tmp[0];
105:  var change = tmp[1];
106:  var findParams = tmp[2];
107:  var changeParams = tmp[3];
108: 
109:  var record = [[find, findParams], [change, changeParams] ];
110:  FillFindChangeFromArray(record);
111:  if (app.changeGrepPreferences.isValid & app.findGrepPreferences.isValid != true) throw(errString);
112: } catch(err) {
113:  // Если произошла ошибка -- вывожу уже подготовленное сообщение
114:   alert (errString);
115:   exit();
116: }
117:  
118:  changeList.push(record );
119: 
120: }
121:  if (changeList.length == 0) {
122:   alert (msg_err.NothingToDoChangesFile+"\n"+changeListName); 
123:  }
124:  app.findGrepPreferences =  NothingEnum.nothing;
125:  app.changeGrepPreferences =  NothingEnum.nothing;
126: }
127: 
128: // -----------------------------------------------------------------------------------------------------//
129: 
130: /** Добавляю уникальные объекты в массив  */
131: function AddToArrayUnique(obj,Iarray) {
132:  var i = Iarray.length; 
133:  while (i--) if (Iarray[i] == obj) return;
134:  Iarray.push(obj);
135: }
136: 
137: 
138: /** objects2Work -- массив объектов с которыми нужно работать */
139: function CalcObjectForHandle(inputObject,objects2Work) {
140:  switch (String(inputObject)) {
141: 
142:    // HandleTextFrame(inputObject);
143:   //  ('handled');
144:     break;
145:    case '[object Story]' :
146:      AddToArrayUnique(inputObject, objects2Work);
147:     break;
148:    case '[object TextFrame]':
149:    case '[object Text]':
150:    case '[object InsertionPoint]':
151:    case '[object Character]': 
152:    case '[object Word]': 
153:    case '[object Line]': 
154:    case '[object Paragraph]': 
155:    case '[object TextColumn]':
156:    
157:      AddToArrayUnique(inputObject.parentStory,objects2Work);
158:      break;
159:    case '[object Group]':
160: /*     var i = inputObject.textFrames.length;
161:       while (i--) AddToArrayUnique(inputObject.textFrames[i].parentStory,objects2Work); */
162: /*     var i = inputObject.groups.length;
163:       while (i--)  CalcObjectForHandle(inputObject.groups[i]);      */
164:      var i = inputObject.allPageItems.length;
165:       while (i--)  CalcObjectForHandle(inputObject.allPageItems[i]);
166:       
167: 
168:      break;
169: 
170:    case '[object Rectangle]':
171:    case '[object GraphicLine]':
172:    case '[object Polygon]':
173:     break;
174:    default:
175:    throw(msg_err.UnsupportedObject+ String(inputObject)) ;
176:    exit();
177:  }
178: }
179: 
 
180: /* временный хлам-подсказки 
181:  Исправление тирешек
182:  \s([~_~=-])(\s)
183:  ^([~_~=-])(\s)
184:  
185:  */
186: 
187: 
188: // Функция обработки объекта "story"
189: function HandleStory(inStory) {
190:  /* app.findGrepPreferences =  NothingEnum.nothing;
191:  app.changeGrepPreferences =  NothingEnum.nothing;
192: */
193: var c = changeList.length;
194: //var  i = changeList.length;
195: var i = 0;
196:    for (; i<c; i++) {
197:  
198: //  while (--i >= 0){
199:   // alert (i);
200:   FillFindChangeFromArray(changeList[i]);
201:   var result = inStory.changeGrep();
202:   //alert (result);
203:  }
204: }
205: 
206: 
207: 
208: /*
209:  Основная функция и ее вызов.
210:  Для пресечения  вызова можно 
211:  объявить переменную doNotStartTextCleanUpMainFunction 
212:  и назначить ей значение отличное от false
213:  */
214: try { 
215:  if (doNotStartTextCleanUpMainFunction== false){
216:   main();
217:  }
218: } catch(err) {
219:  main();
220: } 
221: function main() {
222: 
223:  // определяю активный документ.
224:  try { 
225:   var myDoc = app.activeDocument;
226:  } catch (err) {
227:   alert(msg_err.CantOpenDocument);
228:   exit();
229:  }
230: 
231: 
232:  var selCount = myDoc.selection.length;
233:  var currSelect = myDoc.selection;
234:  var objects2Work=Array();
235:  while (selCount--) CalcObjectForHandle(currSelect[selCount], objects2Work);
236:  var WorkLen = objects2Work.length;
237:  // alert(WorkLen);
238:  PrepareChangeList() ;
239:  
240:  while (WorkLen--) HandleStory(objects2Work[WorkLen]);
241: }
242: 
243: 
244: } catch(err) {
245:  // отлов глобальных ошибок
246:  alert ("Ошибка в ДНК программиста:\n"+err);
247: }
Ну и куда же без файла настроек?


#kst_changeGreep.txt должен находиться в той же папке.

# Файл-регехсп замен. Используется в скрипте greep-замены
# Если первый символ стрики - "#", то строка считается комментарием.
# Сроки короче трех символов в длинну считаются пустыми и пропускаются.
#
#
# формат: одна строка - одна комбинация.
#
# формат строки:
# what#to#paramsWhat#paramsTo
# где what и to -- grep-совместимые регекспы, а params -- параметры поддерживаемые скриптом.
# Indesign Grep re(g)e(x)p1#Indesign Grep ($1)($2) replace#[parameters]#комментарии
#
# [parameters]
# Для каждой строки параметры поиска-замены изначально сброшены в NothingEnum.nothing.
# между "решётками" должен находиться код, который меняет нужный параметр grepXXPreferences;
#
# Пример: нормализация тире. (! заметье, что это - комментарий.)
# (\s+)([~_~=-])(\s+)#$1~_$3##noBreak=true;
# ^([~_~=-])(\s)#~_$2##noBreak=true;
#
# в результате эти строки развернутся в регекспы:
# ищу        (\s+)([~_~=-])(\s+) без критериев
# меняю на   $1~_$3  и присваиваю атрибут "неразрывный текст"
#
#
# Если вы напишете синтаксически не верную строку, 
# то скрипт сообщит вам об этом, указав номер и текст строки,
# затем прекратит работу.
# 
# Если вам потребуется использовать символ #, то записывайте его в виде последовательности \x23
#абвгдеёжзийклмнопрстуфхцчшщъыьэюя


#Удаление лишних пробелов
([ ~m~>~S~s~<~/~.~3~4~%]){2,}#$1##
\s\r#\r##
\r\s#\r##


# нормализация тире.
^[~_~=-]\s#~_~s### Нормализация тире
\s[~_~=-]\s#~s~_~s### Нормализация тире

(\d)\s?[~_~=-]\s?(\d)#$1~=$2### Нормализация перечислений


#короткие слова и предлоги
(\b\w{1,4}\s)#$1##noBreak=true;
#(\s\w{1,4}\b)# $1##noBreak=true;


#предлоги и междометия
#из-за|из-под|по-над|по-за|

# номера и годы
№\s?(\d)#№~<$1##noBreak=true;
(\d)\s?г#$1 г##noBreak=true;

Комментариев нет: