Macro to search and replace without wrapping around document from end back to start

I’m trying to write a macro to step through a writer document searching for specific text (regular expression) and offering to replace it. I’ve modified a recorded macro. This works, but when the choice is made not to replace some of the text, the search replace code loops back to the start of the document finding the same text again. How do I break out of the loop when the final search match is made. I am aware that there is another way of replacing text documented here https://www.openoffice.org/api/basic/man/tutorial/tutorial.pdf but i wish to see the highlighted (selected) text in situ to make my decision to replace or not. This is on Ubuntu. The search replace code will become much more extensive, I just want to get the basics working first.

Sub Ewnhe
Const vbYesNo = 4, vbYes = 6
Dim document as object
Dim dispatcher as object
thisComp = ThisComponent
document = thisComp.CurrentController.Frame
dispatcher = createUnoService(“com.sun.star.frame.DispatchHelper”)
Dim search(21) as new com.sun.star.beans.PropertyValue
Rem TODO Swap the iitems that are changed to be index 0, 1, etc for ease.
search(0).Name = “SearchItem.StyleFamily”
search(0).Value = 2
search(1).Name = “SearchItem.CellType”
search(1).Value = 0
search(2).Name = “SearchItem.RowDirection”
search(2).Value = true
search(3).Name = “SearchItem.AllTables”
search(3).Value = false
search(4).Name = “SearchItem.SearchFiltered”
search(4).Value = false
search(5).Name = “SearchItem.Backward”
search(5).Value = false
search(6).Name = “SearchItem.Pattern”
search(6).Value = false
search(7).Name = “SearchItem.Content”
search(7).Value = false
search(8).Name = “SearchItem.AsianOptions”
search(8).Value = false
search(9).Name = “SearchItem.AlgorithmType”
search(9).Value = 1
search(10).Name = “SearchItem.SearchFlags”
search(10).Value = 65536
search(11).Name = “SearchItem.SearchString”
search(11).Value = “\b(ha|ow)\s+[aeiou]”
search(12).Name = “SearchItem.ReplaceString”
search(12).Value = “”
search(13).Name = “SearchItem.Locale”
search(13).Value = 255
search(14).Name = “SearchItem.ChangedChars”
search(14).Value = 2
search(15).Name = “SearchItem.DeletedChars”
search(15).Value = 2
search(16).Name = “SearchItem.InsertedChars”
search(16).Value = 2
search(17).Name = “SearchItem.TransliterateFlags”
search(17).Value = 1073743104
search(18).Name = “SearchItem.Command”
search(18).Value = 0
search(19).Name = “SearchItem.SearchFormatted”
search(19).Value = false
search(20).Name = “SearchItem.AlgorithmType2”
search(20).Value = 2
search(21).Name = “Quiet”
search(21).Value = true

Dim result As Object
gotoTop = false

dispatcher.executeDispatch(document, “.uno:GoToStartOfDoc”, “”, 0, Array())

Do
result = dispatcher.executeDispatch(document, “.uno:ExecuteSearch”, “”, 0, search())
If IsNull(result) Then Exit Do
selected = thisComp.CurrentSelection.getByIndex(0).getString()
If Len(selected) = 0 Then Exit Do
If UCase(Left(selected, 1)) = “H” Then
correction = “Ha → Hag”
extra = “g”
else
correction = “Ow → Owth”
extra = “th”
Endif
If MsgBox(correction, vbYesNo, “Change”) = vbYes Then
Rem or maybe use setString on the current selection
search(12).Value = Left(selected, 2) + extra + mid(selected, 3)
search(18).Value = 2
dispatcher.executeDispatch(document, “.uno:ExecuteSearch”, “”, 0, search())
search(18).Value = 0
Endif
Loop
End Sub

a bit of XY problem - Wikipedia :neutral_face:
but either way, you probably missed LibreOffice: XTextViewCursor Interface Reference

in your exemple, you can check thisComponent.CurrentController.getViewCursor for Page and/or Position to make sure you’re not looping back over your first occurrence.

Works a charm - thanks very much.

Macro Guides | LibreOffice Documentation - LibreOffice User Guides see mainly Andrew Pitonyak’s book :slight_smile:.

And macro like this?

Sub findReplace1
	dim oDoc as object, oDesc as object, oFound as object, i%, selected$, correction$, extra$
	oDoc=ThisComponent
	oDesc=oDoc.createSearchDescriptor
	with oDesc
		.SearchString="Ha|a." 'your regexp
		.SearchRegularExpression=true
	end with
	oFound=oDoc.CurrentController.ViewCursor 'start searching from visible cursor
	do
		oFound=oDoc.findNext(oFound.End, oDesc)
		if isNull(oFound) then exit do 'nothing is found
		oDoc.CurrentController.select(oFound) 'select the found		
		selected=oFound.String 'found string
		if UCase(Left(selected,  1))="H" then
			correction="Ha → Hag"
			extra="g"
		else
			correction="Ow → Owth"
			extra="th"
		endif
		i=msgbox(correction,  3,  "Change") '3 = Yes/No/Cancel buttons
		if i=6 then 'Yes
			oFound.String=Left(selected,  2) + extra + mid(selected,  3) 'replace
		elseif i=2 then 'Cancel
			exit do
		endif
	loop while true
End Sub

for reference, constants are available at no cost :wink:
MsgBox Function
image

Thanks for info.

This comment was a mistake.