Microsoft Word 2010 VBA: Using regex to find and replace -
i'm trying allow our staff mask middle 8 digits of credit card data in old documents. figure macro using regex find , replace fastest way them. masking pci dss requirement, , there may hundreds or thousands of documents mask data in.
i've had luck below code, identify , modify strings beyond 16 characters standard credit card , i'm not sure how stop false-positives. solved nhahtdh
the following identifies visa, mastercard , amex cards, above mentioned issue. improved adding regex more card types, , adding common characters used break long number.
the below code works, improved. can improve by:
- include luhn algorithm checking
- include additional common number separators (what else commonly used?)
- include other popular card brands
- stop find , replace false-positives (e.g. 44445555666677778 should excluded). solved nhahtdh
sub pci_mask_card_numbers() ' ' macro search document numbers visa, mastercard , amex credit card pans , mask them xs ' dim counter long dim preexisting long ' let user know what's happen dim msg, style, title, response, mystring msg = "the macro attempt mask credit card numbers can identify. e.g. 4444555566667777 become 4444xxxxxxxx7777" style = vbinformation title = "pci dss - credit card masking" response = msgbox(msg, style, title) ' count how many things masked pans final tally correct selection.homekey unit:=wdstory activedocument.content.find while .execute(findtext:="xxxx", forward:=true, format:=true, _ matchwholeword:=true) = true preexisting = preexisting + 1 loop end preexisting = preexisting / 2 ' because masks break counted twice selection.homekey unit:=wdstory activedocument.content.find while .execute(findtext:="xxxxxxxx", forward:=true, format:=true, _ matchwholeword:=false) = true preexisting = preexisting + 1 loop end ' ######## start masking pans ################################################### ' mastercard - 16 digits straight selection.homekey unit:=wdstory selection.find.clearformatting selection.find.replacement.clearformatting selection.find .text = "<([4][0-9]{3})([0-9]{4})([0-9]{4})([0-9]{4})>" .replacement.text = "\1xxxxxxxx\4" .forward = true .wrap = wdfindcontinue .format = false .matchcase = false .matchwholeword = false .matchallwordforms = false .matchsoundslike = false .matchwildcards = true end selection.find.execute replace:=wdreplaceall ' visa - 16 digits straight selection.find .text = "<([5][0-9]{3})([0-9]{4})([0-9]{4})([0-9]{4})>" .replacement.text = "\1xxxxxxxx\4" .forward = true .wrap = wdfindcontinue .format = false .matchcase = false .matchwholeword = false .matchallwordforms = false .matchsoundslike = false .matchwildcards = true end selection.find.execute replace:=wdreplaceall ' amex - 15 digits straight selection.find .text = "<([3][0-9]{2})([0-9]{4})([0-9]{4})([0-9]{4})>" .replacement.text = "\1xxxxxxxx\4" .forward = true .wrap = wdfindcontinue .format = false .matchcase = false .matchwholeword = false .matchallwordforms = false .matchsoundslike = false .matchwildcards = true end selection.find.execute replace:=wdreplaceall ' visa , mastercard - pan broken : selection.find .text = "<([4][0-9]{3})(:[0-9]{4}:[0-9]{4}:)([0-9]{4})>" .replacement.text = "\1:xxxx:xxxx:\3" .forward = true .wrap = wdfindcontinue .format = false .matchcase = false .matchwholeword = false .matchallwordforms = false .matchsoundslike = false .matchwildcards = true end selection.find.execute replace:=wdreplaceall selection.find .text = "<([5][0-9]{3})(:[0-9]{4}:[0-9]{4}:)([0-9]{4})>" .replacement.text = "\1:xxxx:xxxx:\3" .forward = true .wrap = wdfindcontinue .format = false .matchcase = false .matchwholeword = false .matchallwordforms = false .matchsoundslike = false .matchwildcards = true end selection.find.execute replace:=wdreplaceall ' visa , mastercard - pan broken . selection.find .text = "<([5][0-9]{3})(.[0-9]{4}.[0-9]{4}.)([0-9]{4})>" .replacement.text = "\1.xxxx.xxxx.\3" .forward = true .wrap = wdfindcontinue .format = false .matchcase = false .matchwholeword = false .matchallwordforms = false .matchsoundslike = false .matchwildcards = true end selection.find.execute replace:=wdreplaceall selection.find .text = "<([4][0-9]{3})(.[0-9]{4}.[0-9]{4}.)([0-9]{4})>" .replacement.text = "\1.xxxx.xxxx.\3" .forward = true .wrap = wdfindcontinue .format = false .matchcase = false .matchwholeword = false .matchallwordforms = false .matchsoundslike = false .matchwildcards = true end selection.find.execute replace:=wdreplaceall ' visa , mastercard - pan broken spaces selection.find .text = "<([4][0-9]{3})( [0-9]{4} [0-9]{4} )([0-9]{4})>" .replacement.text = "\1 xxxx xxxx \3" .forward = true .wrap = wdfindcontinue .format = false .matchcase = false .matchwholeword = false .matchallwordforms = false .matchsoundslike = false .matchwildcards = true end selection.find.execute replace:=wdreplaceall selection.find .text = "<([5][0-9]{3})( [0-9]{4} [0-9]{4} )([0-9]{4})>" .replacement.text = "\1 xxxx xxxx \3" .forward = true .wrap = wdfindcontinue .format = false .matchcase = false .matchwholeword = false .matchallwordforms = false .matchsoundslike = false .matchwildcards = true end selection.find.execute replace:=wdreplaceall ' visa , mastercard - pan broken - selection.find .text = "<([5][0-9]{3})(-[0-9]{4}-[0-9]{4}-)([0-9]{4})>" .replacement.text = "\1-xxxx-xxxx-\3" .forward = true .wrap = wdfindask .format = false .matchcase = false .matchwholeword = false .matchallwordforms = false .matchsoundslike = false .matchwildcards = true end selection.find.execute replace:=wdreplaceall selection.find .text = "<([4][0-9]{3})(-[0-9]{4}-[0-9]{4}-)([0-9]{4})>" .replacement.text = "\1-xxxx-xxxx-\3" .forward = true .wrap = wdfindask .format = false .matchcase = false .matchwholeword = false .matchallwordforms = false .matchsoundslike = false .matchwildcards = true end selection.find.execute replace:=wdreplaceall selection.homekey unit:=wdstory ' ######## done masking pans ################################################### ' count how many changes done selection.homekey unit:=wdstory activedocument.content.find while .execute(findtext:="xxxx", forward:=true, format:=true, _ matchwholeword:=true) = true counter = counter + 1 loop end counter = counter / 2 ' because masks break counted twice selection.homekey unit:=wdstory activedocument.content.find while .execute(findtext:="xxxxxxxx", forward:=true, format:=true, _ matchwholeword:=false) = true counter = counter + 1 loop end counter = counter – preexisting ' new masks less previous mask-like data ' let user know job done msg = "the macro has masked " & str$(counter) & " credit cards. check results , save file if changes correct. if there issues masking changes, not save file , consult team." style = vbinformation title = "pci dss - credit card masking." & str$(counter) & " cards masked" response = msgbox(msg, style, title) end sub
since seems using word wildcard syntax, can use <
, asserts beginning of word, , >
, asserts end of word prevent pattern matching when text preceded or succeeded letters or numbers (which how seems work simple testing).
using
"([4][0-9]{3})(-[0-9]{4}-[0-9]{4}-)([0-9]{4})"
as example, modify into
"<([4][0-9]{3})(-[0-9]{4}-[0-9]{4}-)([0-9]{4})>"
Comments
Post a Comment