Results 1 to 8 of 8
  1. #1
    New Lounger
    Join Date
    Aug 2012
    Posts
    3
    Thanks
    0
    Thanked 0 Times in 0 Posts

    Word macro for Wildcard Find and Replace with Increment

    I thought that I was close but I'm seeing some weird behavior. A little background. I'm writing a requirements specification and each requirement should have a unique number (e.g. HRS0010, HRS0020). Once the number is established in the first revision of the document it mustn't change; that's why I haven't used something like SEQ, other fields, or lists. What I'd like to be able to do is create Normal paragraphs for each requirement and preface the paragraph with a placeholder text.

    E.g.

    [REQ0000] This is a requirement.

    Once I'm ready, I'd like to run a macro that will wildcard search for the placeholder and replace them all with an incrementing value. I'd like something generic so I should be able to specify the text prefix of the placeholder (the "REQ" in the example) and enter a custom prefix for the replacement (e.g. "HRS" or "SRS"). All this so that something like

    REQ0000 First requirement.
    REQ0000 Second requirement.
    REQ0000 Third requirement.

    becomes

    HRS0010 First requirement.
    HRS0020 Second requirement.
    HRS0030 Third requirement.

    Here is the code that I'm working from.

    Code:
    '
    ' AutoIncReqNumber
    '
    ' Searches through a selection for <custom>#### and replaces the text
    ' with <custom><num> where <num> is an auto-incremented value that
    ' starts at 0 and increments by 10 each time.  The primary use for
    ' this is to assign requirement numbers just before you commit the
    ' draft version of the document.  This will not hold onto old numbers
    ' and will overwrite numbers that already exist so it shouldn't be
    ' used for documents that have already been in the review process
    ' against which people are starting development.
    '
    Sub AutoIncReqNumber()
        Dim iCount As Integer
        Dim strSearchStr As String
        Dim strOutPrefix As String
        Dim strFormatStr As String
    
        ' Get the search prefix that you would like to
        ' replace in the text.  This allows you to search
        ' for already created requirement numbers and
        ' replace them with incremented numbers.  Use with
        ' caution
        strSearchStr = InputBox("Search string for Requirement (REQ, SSS, HRS, etc.)", "Search String", "REQ")
        strSearchStr = UCase(strSearchStr)
        strSearchStr = strSearchStr & "[0-9]{4}"
    
        ' Get the prefix that you would like to use with
        ' the default of SSS for a system specification
        strOutPrefix = InputBox("Type of Requirement (SSS, HRS, SRS, etc.)", "Requirement Type", "SSS")
        strOutPrefix = UCase(strOutPrefix)
    
        ' This is the main part of the find.  It sets up the find
        ' criteria for the regular expression <custom>####
        Selection.Find.ClearFormatting
        Selection.Find.Replacement.ClearFormatting
        iCount = 0
        With Selection.Find
            .Text = strSearchStr
            .Forward = True
            .Wrap = wdFindStop
            .Format = False
            .MatchWildcards = True
            .Execute Replace:=wdReplaceOne
           
            ' Here is the replacement.  The iCount increments by
            ' 10 and the value is formatted into the replacement
            ' string before performing the replacement.
            Do Until Not .Found
                iCount = iCount + 10
                strFormatStr = strOutPrefix & Format(iCount, "0000")
                .Replacement.Text = strFormatStr
                .Execute Replace:=wdReplaceOne
                Selection.MoveRight Unit:=wdCharacter, Count:=1
            Loop
        End With
    End Sub
    Seems to make sense to me but I'm seeing some odd behavior. Things like it will delete the first instance of what it finds and only replace the second instance. Or, it will only replace the first instance but with the number associated with the last instance. Can anyone make heads or tails of this and offer some suggestions?

    Thanks,
    Ben

  2. #2
    Super Moderator
    Join Date
    May 2002
    Location
    Canberra, Australian Capital Territory, Australia
    Posts
    3,899
    Thanks
    0
    Thanked 188 Times in 172 Posts
    Try:
    Code:
    Sub AutoIncReqNumber()
         '
         ' AutoIncReqNumber
         '
         ' Searches through a selection for <custom>#### and replaces the text
         ' with <custom><num> where <num> is an auto-incremented value that
         ' starts at 0 and increments by 10 each time.  The primary use for
         ' this is to assign requirement numbers just before you commit the
         ' draft version of the document.  This will not hold onto old numbers
         ' and will overwrite numbers that already exist so it shouldn't be
         ' used for documents that have already been in the review process
         ' against which people are starting development.
         '
        Dim iCount As Long, strSearchStr As String, strOutPrefix As String
         ' Get the search prefix that you would like to
         ' replace in the text.  This allows you to search
         ' for already created requirement numbers and
         ' replace them with incremented numbers.  Use with
         ' caution
        strSearchStr = UCase(InputBox("Search string for Requirement (REQ, SSS, HRS, etc.)", "Search String", "REQ"))
         ' Get the prefix that you would like to use with
         ' the default of SSS for a system specification
        strOutPrefix = UCase(InputBox("Type of Requirement (SSS, HRS, SRS, etc.)", "Requirement Type", "SSS"))
         ' This is the main part of the find.  It sets up the find
         ' criteria for the regular expression <custom>####
        iCount = 0
        With ActiveDocument.Content
            With .Find
                .ClearFormatting
                .Replacement.ClearFormatting
                .Text = strSearchStr & "[0-9]{4}"
                .Forward = True
                .Wrap = wdFindStop
                .Format = False
                .MatchWildcards = True
                .Execute
            End With
             ' Here is the replacement.  The iCount increments by
             ' 10 and the value is formatted into the replacement
             ' string before performing the replacement.
            While .Find.Found = True
                iCount = iCount + 10
                .Text = strOutPrefix & Format(iCount, "0000")
                .Collapse wdCollapseEnd
                .Find.Execute
            Wend
        End With
    End Sub
    Cheers,

    Paul Edstein
    [MS MVP - Word]

  3. #3
    Star Lounger
    Join Date
    Feb 2011
    Location
    Washington, DC
    Posts
    87
    Thanks
    5
    Thanked 5 Times in 5 Posts
    Another approach entirely would be to use a SEQ field with live numbering right up until the time you were done with the doc or at least done with putting in new requirements. At that point you could use the Word command that changes the numbering from live to fixed text (which exists but I don't remember what it is called right at the moment).

  4. #4
    2 Star Lounger
    Join Date
    Dec 2009
    Location
    Canada
    Posts
    120
    Thanks
    3
    Thanked 20 Times in 18 Posts
    @jweissmn1: The SEQ fields can be converted to text by selecting them and pressing Ctrl-Shift-F9. It is probably a good idea to update the fields first by pressing F9.

    Other field shortcuts include Alt-F9 to toggle the view between field codes and their calculated results -- or Shift-F9 for a single selected field code; F11 and Shift-F11 to jump to the next or previous field code; Ctrl-F11 and Shift-Ctrl-F11 to lock & unlock a field code. If you use field codes, consider using the Word Option to turn on visibility: it causes any calculated redult to display in grey on the screen (but is not printed) so you can see at a glance that it is not ordinary text.

  5. #5
    New Lounger
    Join Date
    Aug 2012
    Posts
    3
    Thanks
    0
    Thanked 0 Times in 0 Posts
    Paul,

    This seems to be working. It appears that the biggest difference was in the Selection versus the ActiveDocument.Content and the .Collapse parameter (still not sure what that one does). Thanks for your help.

    Sincerely,
    Ben

  6. #6
    New Lounger
    Join Date
    Aug 2012
    Posts
    3
    Thanks
    0
    Thanked 0 Times in 0 Posts
    I thought about this one but there are a large number of requirements and the documents contain a large number of other fields, too. It would be very tedious to go through and convert each of the SEQ fields to text; selecting the document and performing the replacement would change all of the other fields to text, too. Thanks for the suggestion.

  7. #7
    Star Lounger
    Join Date
    Feb 2011
    Location
    Washington, DC
    Posts
    87
    Thanks
    5
    Thanked 5 Times in 5 Posts
    Thanks. that will certainly work.

    What I had in mind and have finally found again is the VBA method ConvertNumbersToText. You can use it for a list object, a listformat object, or an entire document.

    ActiveDocument.Lists(1).ConvertNumberstoText

    for example. It will work from the Immediate window or from a macro.

  8. #8
    Super Moderator
    Join Date
    May 2002
    Location
    Canberra, Australian Capital Territory, Australia
    Posts
    3,899
    Thanks
    0
    Thanked 188 Times in 172 Posts
    Quote Originally Posted by bdheard View Post
    It appears that the biggest difference was in the Selection versus the ActiveDocument.Content and the .Collapse parameter (still not sure what that one does).
    Hi Ben,

    Using ActiveDocument ensures the whole document gets processed, rather than just what you might have selected (or from the insertion point to the end of the document). The .Collapse method tells Word to start searching again from the end of the range we've just processed, rather than including it (which would cause an endless loop).
    Cheers,

    Paul Edstein
    [MS MVP - Word]

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •