Replace Specific Text in Text Note (Maintain List Numbering)

Hi All,

I’m looking to replace references to sheets (i.e the sheet number) wherever they appear, throughout all text notes in the project. As a test, I put a word in one of the notes (which I knew wouldn’t show up anywhere else), and was able to successfully replace it with a new word. The problem is, the text notes are made up of numbered lists and the script seems to remove the numbering. As a result, while the text replaces perfectly, the numbering has been removed.

Any thoughts on retaining the number would be appreciated!

Thanks,
Scott



img03

Hey Scott,

This is a big one, and I haven’t tested myself (nor do I have time to do so) so hope you’re ready for some coding…
*deep breath*

Perhaps you can find an easier way around all this?

Currently the OOTB text note nodes do not deal with formatted text objects, only plain text objects. This means you can read the text, but not the formatting associated to it. i do not know of any packages which expose the formatted text options directly.

I suspect that this is because this section of the API is nuts. In fact it’s perhaps a more crazy nested set of classes and object relationships than anything short of curtain wall stuff, and things working consistently is tough on the memory via OOTB nodes. You’re going to feel all of this crazy, as the formatting is mixed (ie: not just a numbered list with a single text format, but a numbered list proceeding a headin with a differing formatting).

You’ll have to go python as a result. I haven’t tried this, but I think that as long as no ‘spaces’ are included in your replacements, this could serve as an initial pseudo code outline.

  1. Get the formatted text object from the text note. This allows you to work in the formatted text class instead of in the text note class.
  2. Get the plain text string from the formatted text object.
  3. Find the new lines, and build a text range for each line so you can pull the paragraph formatting.
  4. Find the white space (tabs, spaces), and build a text range for each word so you can pull the word formatting.
  5. Pull the desired paragraph format formatting from the formatted text object (#1) using the paragraph ranges (#3).
  6. Pull the desired word formatting from the formatted text object (#1) using the word ranges (#4).
  7. Change the words in your strings as desired.
  8. Get the new line break ranges in the replacement string (#7), and build a text range for each so you can set your paragraph formatting.
  9. For each range in the paragraph ranges, find the formatting for the matching line, and if it matches the formatting of the previous line merge the range with the previous range.
  10. For each range in the word break ranges, find the formatting for the matching word, and if it matches the formatting of the previous line merge the range with the previous range.
  11. Build a new formatted text object from the replaced text (#7).
  12. Set the paragraph formatting for the new formatted text object using the paragraph formats (#5) and ranges (#9).
  13. Set the word formatting for the new formatted text object using the word formats (#6) and ranges (#10).
  14. Cross your fingers and hope.

Note that for the paragraph and word formatting you will need to get and then set multiple methods (ie: Indent Level,, ListStartNumber, ListType, etc.).

If it is super simple numbering this python script will do it:

It is important that your text note list and the replacement list are the same lengths for this version. This isn’t a perfect solution, but it offers some reasoning for how the Revit API goes about this madness. :crazy_face:

Example:

and the Python Script:
import clr

clr.AddReference('RevitAPI')
from Autodesk.Revit.DB import *
from Autodesk.Revit.DB.Structure import *

clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

doc = DocumentManager.Instance.CurrentDBDocument
uidoc=DocumentManager.Instance.CurrentUIApplication.ActiveUIDocument


def SetTextWithSimpleNumbering(textNote, replacementText):
	#start a transaction
	TransactionManager.Instance.EnsureInTransaction(doc)
	#get the formatted text, it's original range and list type
	formatText = textNote.GetFormattedText()
	range = formatText.AsTextRange()
	listType = formatText.GetListType(range)
	#set the new text
	formatText.SetPlainText(range,replacementText)
	#get the new range and set the list type back
	newRange = formatText.AsTextRange()
	formatText.SetListType(newRange, listType)
	textNote.SetFormattedText(formatText)
	#finish the transaction
	TransactionManager.Instance.TransactionTaskDone()
	return textNote

#Preparing input from dynamo to revit
textNote = UnwrapElement(IN[0])
replacementText = IN[1]

# return the results
if isinstance(IN[0], list): OUT = [SetTextWithSimpleNumbering(t,r) for t,r in zip(textNote,replacementText)]
else: OUT = SetTextWithSimpleNumbering(textNote,replacementText)

and the DYN:
SimpleSetTextWithNumbering.dyn (10.2 KB)

3 Likes

Thanks Jacob and John! The Python script seemed to work more than it didn’t, so that’s good. When it didn’t work, though, the attached error appeared.img05

yeah that is going to be difficult to debug. There’s a chance that text note didn’t have numbering?

Would the fact that some of the text notes are inside Detail Groups and some are not, have any affect on things?

yes

Detail groups and Mixed formatting types would also be a potential issue (hence my whole idea of doing all this other junk which shouldn’t be a thing you have to worry about but somehow here we are).

Well, I just started, earlier today, learning Python as quickly as I can. :grin:

1 Like

Hello
another solution with Find() method

import clr
import sys
import System
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *

clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import *

clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc = DocumentManager.Instance.CurrentDBDocument

pf_path = System.Environment.GetFolderPath(System.Environment.SpecialFolder.ProgramFilesX86)
sys.path.append(pf_path + '\\IronPython 2.7\\Lib')

def searchReplace(textNote, searchN, replaceN):

	TransactionManager.Instance.EnsureInTransaction(doc)
	
	formatText = textNote.GetFormattedText()
	rangeFormat = formatText.Find(searchN, 0, True, True)
	if rangeFormat.Length > 0:
		formatText.SetPlainText(rangeFormat,replaceN)
		textNote.SetFormattedText(formatText)

	TransactionManager.Instance.TransactionTaskDone()
	return textNote

toList = lambda x : x if hasattr(x, '__iter__') else [x]

textNotes = toList(UnwrapElement(IN[0]))
search = IN[1]
replace = IN[2]

OUT = [searchReplace(x, search, replace) for x in textNotes if isinstance(x, TextNote)]
5 Likes

@c.poupin - This worked perfectly for multiple instances in multiple text notes both inside and and outside of detail groups. Thanks!

Now here’s the second part: this works if I need to replace specific text, with specific other text. I have a specific format for sheet numbers that are referenced within the text notes: A0.00. I need to replace them with the following format: A-000. Each project could have different sheet notes referenced throughout all of the text notes in the project.

I’ve created another script to apply this change to all sheet numbers, for the sheets themselves (see the 3-part images).

Basically, it:

  1. Gets a list of all the sheets, gets their values for a parameter called “Sheet Discipline”, and then filters out any sheets that have 3 specific values for that “Sheet Discipline” parameter.
  2. Then, it removes the period from all of the sheet numbers.
  3. Then, it splits the strings of all of the sheet numbers into 2 lists where one list has the letter(s) for each sheet number, and the other has the numbers for each sheet number.
  4. Then a “-” is added to the end of all of the items in the letter list.
  5. The 2 lists are then recombined to have all of the sheet numbers have the correct format (i.e. A-000, instead of A0.00).
  6. Finally, all of the Sheet Numbers are replaced with the newly formatted value.

The reason I mention all that is because it’s able to make the change to any sheet number that happens to exist (each project will have different sheet numbers). As mentioned above, I need the script that we’re talking about here to do the same thing.

Any thoughts on how I can implement that (and whether or not the script I built that I describe above could be useful for this)?

Thanks VERY much as always!
Scott

1 Like

Did you ever figure this out? I am trying to do the same exact thing right now replacing text notes. I have about 170 sheets where I need to replace refernce notes checking for all of them in the project. The sheet number chanign graph I made works great with reading Excel. I am having trouble with doing this batch changing process with text notes though. and I do not want to manually enter each sheet one at a time to chage.

any help would be awesome thanks!