Data panel
Find and Replace Attributes
Replaces text inside block attribute values across the drawing, the selection or blocks you pick, in every tag or just one, with or without matching case.
On the ribbonButton, Data panel
NeedsAn open drawing
Command
PYFINDANDREPLACEATTRIBUTESAlias
FRAShortcutNone set (bind one in Shortcuts)
What it does#
Replaces one piece of text with another inside attribute values, in the block references
you choose, in every attribute or only in one tag. AutoCAD's FIND can search attribute text
too, but it cannot keep to one tag. The text is plain text, never a pattern, so a
* or a . means itself. The command is
PYFINDANDREPLACEATTRIBUTES.
How to use it#
- Optionally select the block references to work on.
- Click Find and Replace Attributes.
- Type the text to find. Your last search is filled in.
- Type what to put instead. Leave it empty to remove the text.
- Choose where: Selection (offered when something is selected, with how many objects), Whole drawing, or Pick blocks to select them at the command line now.
- Choose which attribute: Every tag, or one tag from the list of tags those blocks carry. The list has a search box.
- Choose Ignore case or Match case. Your last choice is offered first.
- The changes are made straight away, and a toast says how many values changed in how
many block references.
Utakes them back.
Good to know / limits#
- There is no preview: the replacement happens as soon as you choose the case option. Run
Blocks to Excel first if you want to see what is there,
and rely on
Uif the result is wrong. - It replaces every occurrence inside a value, not just whole values. Replacing
1with2turns101into202. - Blocks on locked layers are left alone, and the toast says how many could not be changed.
- The find and replace text and the case choice are remembered under
%APPDATA%\pyACAD\settings, for every drawing. - Only references placed directly in model space or on a layout are searched (or those you select or pick). Xrefs and blocks nested inside other blocks are not.
- Plain text in the drawing (TEXT, MTEXT) is not touched: only attribute values.
Other uses#
- Change a project number or revision letter in every title block at once, in the one tag that holds it.
- Rename a room or system prefix across all the tags that carry it.
- Remove a stray suffix, such as
-OLD, by replacing it with nothing.
Source#
The tool's own files, word for word as shipped in Data.panel/Find_Replace_Attributes.pushbutton. Every pyACAD tool is an ordinary bundle: copy these into your own extension and change what you like.
script.py Runs on a click. View on GitHub# -*- coding: utf-8 -*-
"""Find and replace text inside block attribute values.
Asks what to find and what to put instead (both remembered for next time),
then where: the whole drawing, the selected blocks, or blocks picked now. Then
which attribute (every tag, or one) and whether case must match. The text is
plain, never a pattern. Every change is one Undo; blocks on locked layers are
left alone and reported.
"""
from pyacad import blocks, forms, script, sel, toast
__title__ = 'Find and Replace Attributes'
TITLE = 'Find and Replace Attributes'
DEFAULTS = {'find': '', 'replace': '', 'match_case': False}
WHOLE = 'Whole drawing'
PICK = 'Pick blocks'
ALL_TAGS = 'Every tag'
IGNORE_CASE = 'Ignore case'
MATCH_CASE = 'Match case'
def plural(count, word):
return '%d %s%s' % (count, word, '' if count == 1 else 's')
def choose_refs():
"""The block reference snapshots to search, or None when cancelled."""
picked = sel.current()
options = [WHOLE]
selected = None
if picked:
selected = 'Selection (%s)' % plural(len(picked), 'object')
options.insert(0, selected)
options.append(PICK)
where = forms.ask_options('Replace in which block references?', options, TITLE)
if where is None:
return None
if where == WHOLE:
return blocks.snapshots()
if where == PICK:
picked = sel.pick_many('Select block references: ')
if not picked:
return None
return blocks.snapshots(picked)
def run():
if script.get_document_path() is None:
toast.warning('No drawing is open', 'Open a drawing, then run %s' % TITLE)
return
saved = script.get_config(DEFAULTS)
find = forms.ask_string('Find this text in attribute values:', saved['find'], TITLE)
if find is None:
return
if not find:
toast.info('Nothing to find', 'Type the text to look for')
return
replace = forms.ask_string('Replace "%s" with (leave empty to remove it):' % find,
saved['replace'], TITLE)
if replace is None:
return
refs = choose_refs()
if refs is None:
return
tags = blocks.attribute_tags(refs)
if not tags:
toast.info('No attributes to search', 'None of those block references has attributes')
return
tag = forms.select_from_list([(ALL_TAGS, '')] + tags, title=TITLE,
prompt='Replace in which attribute?')
if tag is None:
return
case = forms.ask_options('Match case?', [IGNORE_CASE, MATCH_CASE] if not saved['match_case']
else [MATCH_CASE, IGNORE_CASE], TITLE)
if case is None:
return
match_case = case == MATCH_CASE
script.save_config({'find': find, 'replace': replace, 'match_case': match_case})
found = blocks.replace_in_attributes(refs, find, replace, case_sensitive=match_case,
tag=tag or None)
if not found:
toast.info('No matches', 'No attribute value contains "%s"' % find)
return
result = blocks.apply_changes(dict((handle, {'attributes': values})
for handle, values in found.items()))
detail = 'in %s' % plural(result['updated'], 'block reference')
if result['failed']:
detail += '; %s could not be changed (locked layer?)' % plural(len(result['failed']), 'block')
toast.warning('Replaced %s' % plural(result['values'], 'value'), detail)
else:
toast.success('Replaced %s' % plural(result['values'], 'value'), detail)
if '__commandpath__' in globals():
run()bundle.yaml The bundle contract: the keys pyACAD reads for this tool. View on GitHubtitle: Find and Replace Attributes
tooltip: Replaces text in block attribute values across the drawing, the selection or blocks you pick, in every tag or just one, with or without matching case. One Undo takes it all back.
context: doc
keytip: DF
alias: FRA