Тема: Простой перенумератор

Давно что-то не было перенумераторов в этой теме.

Написал перенумератор, может кому понравится и пригодится.
Используем уже больше года, самая востребованная программа в отделе.
Занимаемся слаботочкой, поэтому чертежи состоят из большого количества разных обозначений в виде блоков с атрибутами.
Блоков может быть сотни. Кто пожарку, охранку СКУД делают меня понимают.

Перенумераторов много разных, но слишком много вопросов они задают.
Здесь все просто. Нужно, конечно, сделать иконку и вызывать через нее, так удобнее.
Скажем у вас пара десятков блоков, которые надо перенумеровать последовательно в порядке возрастания.
Вы выбираете тот, который будет первым и его обозначение будет служить в качестве образца.
Соответственно ручками его переименовываете. Потом вызываете программу и по ее просьбе кликаете по образцу.
И далее кликая по следующим блокам вы меняете их обозначение на образец, каждый раз увеличивая порядковый номер.
То же можно делать если над обозначениями просто текст.
Образец обязательно должен оканчиваться цифрой, это проверяется. Перенумерация производится только по возрастанию.
Работает в 2006 АКАДе. В других не проверял.
Спасибо всем корифеям этого форума, чьи программы или куски  программ я использовал и по чьим программам я чему-то научился.

;;==========================================================================
;;;;            Рабочая программа перенумерации  DTEXT, MTEXT,  атрибутов Блоков
;;;;                Гуськов Вячеслав  (  aka guslav)    11-01-08
;;;;==========================================================================
(defun C:rnm  ( / rnm:Pref rnm:Start Str curText  curStr)
(vl-load-com)
(setq Str (gu-ent-text )); выбрали образец  и он правильный
(setq rnm:Pref (car Str ));
(setq rnm:Start (cdr Str));и разложили на переменную и постоянную составляющие
(setq rnm:Start (itoa (+ 1 (atoi rnm:Start)))); Увеличили переменную часть на 1 для следущего выбора
(while T
(setq curStr(strcat rnm:Pref rnm:Start)) 
(setq rnm:Start (atoi rnm:Start))
(setq curText  (car  (nentsel "\n>>    Выберите следующие значения  DText/MText/атрибут блока для изменения или Esc чтобы завершить программу ")))
        (if
        (and  curText(member(cdr(assoc 0(entget curText))) '("TEXT" "MTEXT" "ATTRIB"))); end and
            (progn
                (vla-put-TextString (vlax-ename->vla-object curText)curStr)
                (setq rnm:Start(1+ rnm:Start))
            ); end progn
                (princ "\n<< Ошибка выбора объекта. Это не  DText, MText или атрибут блока ! >>")
        ); end if
    (setq rnm:Start (itoa rnm:Start))
  ); end while
  (princ)
); end of 
;;=====================================================================
;;====================================================================
  (defun *error* (msg) (princ "\n<<  Принудительное завершение работы программы  >>")
    (cond
      ((not msg))
      ((member msg '("Function cancelled" "quit / exit abort")))
      ((princ (strcat "\nError: " msg))
       (cond (*debug* (vl-bt)))
       )
      ) ;_ end of cond
        ) ;_ end of defun
      (princ "\n>>  Для запуска набери rnm, для справки набери rnm? " )
      (princ)
;;==========================================================================
;;Функция определения имени  выбранного примитива - рабочая
;;==========================================================================
(defun  gu-ent-text ( / nm action b1 vb)
(while (= action nil)
(while (null (and nm (car (member nm  '("TEXT" "MTEXT" "INS ERT"))))); работает строка
        (setq bl (entsel "\n\n>>  ВЫБЕРИTE КУРСОРОМ  НА ЧЕРТЕЖЕ ИСХОДНЫЙ БЛОК, ТЕХТ или МТЕКСТ (  Для выхода нажмите ESC )"))
            (while (null bl) (setq bl (entsel "\n<<  ОБЪЕКТ НЕ ВЫБРАН, ПОВТОРИTE  ( Для выхода нажмите ESC ) >>")))
        (setq nm (cdr (assoc 0 (entget (car bl)))))
            (if (and nm (member nm  '("TEXT" "MTEXT" "INS ERT"))) (princ "\n" ) (princ "\n<<  Ошибка. Неправильный выбор объекта  >>")
            );if
);while
(setq action (gu-GetConstVarNumber 
(cond 
((= nm "INS ERT")(bl-name bl))
((= nm "TEXT")(cdr (assoc 1 (entget (car bl)))))
((= nm "MTEXT")(  _kpblc-clear-mtext (cdr (assoc 1 (entget(car bl)))))); Вариант крыса c форматированием
); cond
));setq
(if (= action nil) 
(princ "\n<<  Ошибка. У объекта нет изменяемой части  >>")
)
(setq bl nil nm nil vb action)
);while
(princ "<<  Выбрано исходное значение ") (princ (strcat (car vb ) (cdr vb)  "   >>"))
(setq vb action)
); end defun
;===============================================================================
(defun bl-name ( blk / block_data bln) 
(setq bln blk)
(setq block_data (get-all-atts (vlax-ename->vla-object (car bln))))
(setq blk (cdar  block_data));Выбираем 2-й из первого
)
(defun get-all-atts (obj)
    (if  (and obj
       (vlax-property-available-p obj 'Hasattributes)
       (eq :vlax-true (vla-get-hasattributes obj)))
      (vl-catch-all-apply
  (function
    (lambda ()
      (mapcar (function (lambda (x)
    (cons (vla-get-tagstring x)
      (vla-get-textstring x))))
        (append (vlax-invoke obj 'Getattributes)
          (vlax-invoke obj 'Getconstantattributes))))))))
;;====================================================================================== 
;|====================================================================================== 
;;             Функция сносит форматирование многострочного текста. Удаляются символы "{"   
;;           и "}", поскольку именно символ "}" является окончанием применения определенного
;;          фонта. Удаляются наборы типа {fTimes New Roman|b0|i0|c204|p18; и т.п.                     
;;           Параметры вызова:
;;           tring-to-normalize  — строка, которую надо нормализовать
;;           Примеры вызова:
;;           (  _kpblc-clear-mtext (cdr (assoc 1 (entget(car(entsel))))))
;;           для выбранного многострочного текста очищает форматирование.
;;              Редакция VVA
;;=============================================================================|;
(defun _kpblc-clear-mtext (string-to-normalize     /
         sub_string       sub_pos         left_string
         right_string
         )
  (if (or
  (setq sub_pos (vl-string-search "{f" string-to-normalize))
  (setq sub_pos (vl-string-search "{\\" string-to-normalize))
  (setq sub_pos (vl-string-search "\\f" string-to-normalize))
  (setq sub_pos (vl-string-search "{\\f" string-to-normalize))
  ) ;_ end of or
    (progn
      (setq left_string      ;все, что до "{"
       (vl-string-trim
         "{"
         (substr
     string-to-normalize
     1
     (vl-string-position
       (ascii "\\")
       string-to-normalize
       sub_pos
       ) ;_ end of vl-string-position
     ) ;_ end of substr
         ) ;_ end of vl-string-trim
      ) ;_ end of setq

      (if (vl-string-position
      (ascii ";")
      string-to-normalize
      sub_pos
      ) ;_ end of vl-string-position
  (setq right_string    ;все, что между {f и ;
         (substr
     string-to-normalize
     (+ (vl-string-position
          (ascii ";")
          string-to-normalize
          sub_pos
          ) ;_ end of vl-string-position
        2
        ) ;_ end of +
     ) ;_ end of substr
        ) ;_ end of setq
  (setq right_string "")
  ) ;_ end of if
      (_kpblc-clear-mtext (strcat left_string right_string))
      ) ;_ end of progn
    (vl-list->str ing
      (vl-remove
  (ascii "}")
  (vl-string->list string-to-normalize)
  ) ;_ end of vl-remove
      ) ;_ end of vl-list->string
    ) ;_ end of if
  ) ;_ end of defun
;; ================================================================================
;; Функция выделения из текстовой цепочки изменяемой и постоянных частей, помещаемых в список
;; Изменяемая часть - целое число с правой стороны текста до первого символа-не числа,
;; например,  ABC4/55 - здесь 55 - переменная часть, ABC4/ - постоянная часть
;;                                
;;        Гуськов Вячеслав  (  aka guslav )                                                
;;==================================================    
(defun gu-GetConstVarNumber ( CurStr / LengthSpis  Spis SpisVar SpisConst num)
(setq Spis (vl-string->list CurStr));  число и переводим в список чисел
(setq LengthSpis (length Spis)); Длина всего символа 
(setq SpisVar (list))
(setq SpisConst (list))
(setq LengthSpis (- LengthSpis 1))
(setq num (nth LengthSpis Spis)); первый элемент перед входом в цикл
(while ( and (>= LengthSpis 0) (> num 47) (< num 58)) 
        (setq num (nth LengthSpis Spis))
    (if (and (> num 47) (< num 58))
        (setq SpisVar ( cons num SpisVar))
        (setq LengthSpis (+ LengthSpis 1)); попалось не число, увеличиваем на 1 ,чтобы его не потерять при выходе из цикла 
    );if
        (setq LengthSpis (- LengthSpis 1))
); while
(while (>= LengthSpis 0)
        (se tq num (nth LengthSpis Spis))
        (se tq SpisConst( cons num SpisConst))
        (se tq LengthSpis (- LengthSpis 1))
); while
(if (/= SpisVar nil)
(cons (vl-list->string SpisConst) (vl-list->string SpisVar))
)
);defun
;;============================================================================================================
(defun C:RNM? ( / )
(alert " 
    Это программа для последовательной перенумерации любых текстов и обозначений блоков на чертеже.

    Для начала вы выбираете курсором на чертеже первое обозначение блока или какой-то текст, как образец.
    
    Обязательное условие:  текст или обозначение должны заканчиваться хотя бы одной цифрой.    
    
    После этого выбираете следующий объект, который будете менять.    
    
    Выбранное обозначение блока или текст примет вид исходного обозначения, увеличенного на 1.
    
    Выбирая  объекты один за другим, вы получите цепочку последовательно пронумерованных объектов.    
    
    Для запуска программы наберите  rnm  в командной строке АвтоКада.  Чтобы получать диагностические 
    
    сообщения программы, желательно открыть 2-3 строки диагностической области над командной строкой.    
    
    Внимание: при работе с блоками при первоначальном выборе образца можно  выбрать курсором   любое место блока,    

    но при дальнейшем переименовании блоков необходимо выбирать курсором  только  атрибут блока,
    
    т.е непосредственно  его текстовое обозначение.    
    
    Второе. При работе с МMTEXT он не должен иметь переносов, т.е должен быть однострочным.
    
    Третье. В конце обозначения не должно быть пробелов, на чертеже их не видно,но программа примет их за нецифру.
    
    
                        Все вопросы к Гуськову Вячеславу 
);alert
;;============================================================================================================================
 (princ)
);defun

(изменено: Victor, 23 сентября 2009г. 11:12:10)

Re: Простой перенумератор

Попробуйте автоматический перенумератор. Пока для текстов вида ABC123. Запуск tx1

(defun f_last_num ( stroka / len i flag lst nm_len)
(setq len (strlen stroka))
(setq i -1 flag 0 lst_str nil beg_str stroka) 
(repeat len
 (setq i (+ 1 i))
 (setq lst (substr stroka (- len i) 1))
 (if (and (< 47 (ascii lst))(> 58 (ascii lst))(= 0 flag))
     (setq lst_str (substr stroka(- len i)(+ 1 i)))(setq flag 1))
)
(if (/= lst_str nil)
    (progn
    (setq lst_len (strlen lst_str))
    (setq beg_str (substr stroka 1 (- len lst_len)))
    (setq lst_num (atoi lst_str))
    ) ;progn
(setq lst_num nil))
)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun c:tx1( / f_txt fp_txt ftx_str fbeg_str nameset i
                 setlength sp _txt p_txt st_txt txtnum st_num p_new)
(setq f_txt (car (entsel)))
(setq fp_txt (assoc 1(entget f_txt))) 
(setq ftx_str (cdr fp_txt))
(f_last_num ftx_str)
(setq fbeg_str beg_str flst_num lst_num)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(setq nameset (ssget "_X" '(( 0 . "TEXT"))))
(setq setlength (sslength nameset))
(setq i -1)
(repeat setlength
 (setq i (1+ i))
 (setq sp _txt (entget (ssname nameset i)))
 (setq p_txt  (assoc 1 sp _txt))
 (setq st_txt (cdr p_txt))
 (f_last_num st_txt)
 (if (and(= fbeg_str beg_str)(>= lst_num flst_num)(/= lst_num nil)) 
     (progn
     (setq txtnum (+ 1 lst_num))
     (setq st_num (itoa txtnum))
     (setq st_new (strcat beg_str st_num))
     (setq p_new  (cons 1 st_new))
     (setq sp _txt (subst p_new p_txt sp _txt))
     (entmod sp _txt)
     (entupd (cdr (assoc -1 sp _txt)))
     ) ;progn
 ) ;if
) ;repeat
)

(изменено: Nikolay 2, 17 января 2010г. 15:29:26)

Re: Простой перенумератор

Разрешите приподнять тему

guslav пишет:

Блоков может быть сотни. Кто пожарку, охранку СКУД делают меня понимают.

Как раз тот случай, что-то лисп не работает, т.е для текста, содержащего только цифровые значения,работает, а вот при наличии в тексте буквенных значений выдает: Error: no function definition: SE
Использую ACad2008rus+SP1. Ниже приведен весь листинг по F2
Команда: _appload rnm.lsp успешно загружено.
Команда:
>>  Для запуска набери rnm, для справки набери rnm?
<<  Принудительное завершение работы программы  >>
Error: неверно сформированная строка на входе
Команда:
Команда: rnm
>>  ВЫБЕРИTE КУРСОРОМ  НА ЧЕРТЕЖЕ ИСХОДНЫЙ БЛОК, ТЕХТ или МТЕКСТ (  Для выхода
нажмите ESC )
<<  Принудительное завершение работы программы  >>
Error: no function definition: SE
Смущает вот эта запись: Error: неверно сформированная строка на входе
Код скопирован весь, и вроде все верно прописалось в lsp, просьба помочь запустить.

Re: Простой перенумератор

Много лишних пробелов

Re: Простой перенумератор

Victor пишет:

Много лишних пробелов

А где конкретно, подскажешь?

Re: Простой перенумератор

INS ERT, str ing, se tq ,а может и ещё. Спрашивай  автора.

Re: Простой перенумератор

Victor пишет:

INS ERT, str ing, se tq ,а может и ещё. Спрашивай автора.

Спасибо, помогло. Только обнаружил баг, значение K1-OT2.002.001 при обработке программой принимает выражение K1-OT2.002.2, т.е. 001 преобразуется в 2. Задал вопрос автору....

Re: Простой перенумератор

После вставки  программы вообще непонятно, откуда появились лишние пробелы, я просто не ожидал такого и листинг здесь на форуме не проверил  :cry: У меня-то на диске все нормально, пробелов нет и не было.

По поводу того, что если есть так называемые незначащие нули перед числом и они убираются - да, есть такое дело. Т.е. если начальное число 001, то последующие числа будут 2, 3, 4 и т.д, так как при преобразаваниях из текста в целое  число (atoi) эти нули отбрасываются.

Дело в том, что у нас не бывает обозначений такого вида с незначащими нулями, поэтому такой баг я даже и не предполагал. А что можно сделать, пока не знаю, увы. Получается, нужно специально вводить подпрограмму для отслеживания ситуации с незначащими нулями чтобы их восстанавливать.

(изменено: Nikolay 2, 19 января 2010г. 07:45:42)

Re: Простой перенумератор

guslav пишет:

А что можно сделать, пока не знаю, увы. Получается, нужно специально вводить подпрограмму для отслеживания ситуации с незначащими нулями чтобы их восстанавливать.

"Думай боярин, думай..." @к/ф "Иван Васильевич меняет профессию". А у нас вот такой классификатор оборудования, т.е. часто встречаются объекты (сборки) имеющие сотню и более изделий. Просьба, в том числе и  к форумчанам, исправить эту проблему. Ну и код (без пробелов) обновить бы...

(изменено: Valery Brelovsky, 19 февраля 2010г. 07:52:34)

Re: Простой перенумератор

Victor,
А как он работает? :)

Re: Простой перенумератор

Может это подойдет? Редактор списков, в котором есть перенумератор... Текст, МТекст, блоки с атрибутами: http://ifolder.ru/8700385

Re: Простой перенумератор

Valery Brelovsky пишет:

А как он работает?

Про мой что ли? Ищет все тексты вида АБВГД12345, по маске АБВГД и к цифровой части добавляет 1,
но только к числам которые больше 12345, к тем которые меньше не добавляет. Это принцип перенумерации, если вдруг в середине надо добавить номер, а что делать с теми номерами которые больше? Перенумеровывать вручную?

(изменено: Valery Brelovsky, 22 февраля 2010г. 06:14:18)

Re: Простой перенумератор

Victor пишет:

Про мой что ли? Ищет все тексты вида АБВГД12345, по маске АБВГД и к цифровой части добавляет 1, но только к числам которые больше 12345, к тем которые меньше не добавляет. Это принцип перенумерации, если вдруг в середине надо добавить номер, а что делать с теми номерами которые больше? Перенумеровывать вручную?

Да про автоматический пере нумератор. Вопрос получился не очень корректный.
Т.е. 1 получить нельзя что ли. Я что то не догоняю. И что относительно атрибутов блока. :)

(изменено: Victor, 11 апреля 2010г. 23:37:38)

Re: Простой перенумератор

С блоками проблема что нужно указать название блока в программе в строке (setq nameset (ssget "x" '(( 0 . "INS ERT")(2 . "blok"))))
И ещё интересный вопрос, какой атрибут надо проверять. Здесь проверяется 1 атрибут.

(defun f_last_num ( stroka / len i flag lst nm_len)
(setq len (strlen stroka))
(setq i -1 flag 0 lst_str nil beg_str stroka) 
(repeat len
 (setq i (+ 1 i))
 (setq lst (substr stroka (- len i) 1))
 (if (and (< 47 (ascii lst))(> 58 (ascii lst))(= 0 flag))
     (setq lst_str (substr stroka(- len i)(+ 1 i)))(setq flag 1))
)
(if (/= lst_str nil)
    (progn
    (setq lst_len (strlen lst_str))
    (setq beg_str (substr stroka 1 (- len lst_len)))
    (setq lst_num (atoi lst_str))
    ) ;progn
(setq lst_num nil))
)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun c:a+1( / f_txt fp_txt ftx_str fbeg_str nameset i
                 setlength sp_txt p_txt st_txt txtnum st_num p_new)
(setq f_txt (car (entsel)))
(setq fp_txt (assoc 1(entget (entnext f_txt)))) 
(setq ftx_str (cdr fp_txt))
(f_last_num ftx_str)
(setq fbeg_str beg_str flst_num lst_num)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(setq nameset (ssget "x" '(( 0 . "INS ERT")(2 . "blok"))))
(setq setlength (sslength nameset))
(PRINC setlength)
(setq i -1)
(repeat setlength
 (setq i (1+ i))
 (setq sp_txt (entget(entnext(ssname nameset i))))
 (PRINC sp_txt)
 (setq p_txt  (assoc 1 sp_txt))
 (setq st_txt (cdr p_txt))
 (f_last_num st_txt)
 (if (and(= fbeg_str beg_str)(>= lst_num flst_num)(/= lst_num nil)) 
     (progn
     (setq txtnum (+ 1 lst_num))
     (setq st_num (itoa txtnum))
     (setq st_new (strcat beg_str st_num))
     (se tq p_new  (cons 1 st_new))
     (se tq sp_txt (subst p_new p_txt sp_txt))
     (entmod sp_txt)
     (entupd (cdr (assoc -1 sp_txt)))
     ) ;progn
 ) ;if
) ;repeat
)