Replace Nth Occurrence of String

I am trying to put together a script using Script Editor to replace the nth occurrence of a string of text in a line.
The AppleScript - A Comprehensive Guide … (Hanaan Rosenthal) does not appear to cover this having checked through the index.

Any pointers would be greatly appreciated.

Thanks :slight_smile:

Give us a sample of the text you want to deal with. Finding and replacing (even with nothing) is fairly straight-forward and simple additions to those scripts will count occurrences.

Adam,

Thanks for your reply. I have lines of text in a file such as:

65,O’Flaherty; Thomas Jamestown Jaguars 743,92,42

What I need to be able to script is the replacement of the second space in the line with a comma so the result is:

65,O’Flaherty; Thomas,Jamestown Jaguars 743,92,42

Thanks again for your help. :slight_smile:

Adam,

I don’t know if this is any more help but this is the existing script so far:

on open var_FileName
	
	tell application "TextWrangler"
		activate
		
		open var_FileName
		
		replace "  " using "\\t" searching in text 1 of text window 1 options {search mode:literal, starting at top:true, wrap around:false, backwards:false, case sensitive:false, match words:false, extend selection:false}
		replace "\\t\\t" using "\\t" searching in text 1 of text window 1 options {search mode:literal, starting at top:true, wrap around:false, backwards:false, case sensitive:false, match words:false, extend selection:false}
		replace "\\t\\t" using "\\t" searching in text 1 of text window 1 options {search mode:literal, starting at top:true, wrap around:false, backwards:false, case sensitive:false, match words:false, extend selection:false}
		replace "\\t\\t" using "\\t" searching in text 1 of text window 1 options {search mode:literal, starting at top:true, wrap around:false, backwards:false, case sensitive:false, match words:false, extend selection:false}
		replace "\\t\\t" using "\\t" searching in text 1 of text window 1 options {search mode:literal, starting at top:true, wrap around:false, backwards:false, case sensitive:false, match words:false, extend selection:false}
		replace "\\t\\t" using "\\t" searching in text 1 of text window 1 options {search mode:literal, starting at top:true, wrap around:false, backwards:false, case sensitive:false, match words:false, extend selection:false}
		replace "\\t\\t" using "\\t" searching in text 1 of text window 1 options {search mode:literal, starting at top:true, wrap around:false, backwards:false, case sensitive:false, match words:false, extend selection:false}
		replace "," using ";" searching in text 1 of text window 1 options {search mode:literal, starting at top:true, wrap around:false, backwards:false, case sensitive:false, match words:false, extend selection:false}
		replace "\\t" using "," searching in text 1 of text window 1 options {search mode:literal, starting at top:true, wrap around:false, backwards:false, case sensitive:false, match words:false, extend selection:false}
		replace ", " using "," searching in text 1 of text window 1 options {search mode:literal, starting at top:true, wrap around:false, backwards:false, case sensitive:false, match words:false, extend selection:false}
		replace ",\\r," using "\\r" searching in text 1 of text window 1 options {search mode:literal, starting at top:true, wrap around:false, backwards:false, case sensitive:false, match words:false, extend selection:false}
		replace "\\r," using "\\r" searching in text 1 of text window 1 options {search mode:literal, starting at top:true, wrap around:false, backwards:false, case sensitive:false, match words:false, extend selection:false}
		replace "'" using "’" searching in text 1 of text window 1 options {search mode:literal, starting at top:true, wrap around:false, backwards:false, case sensitive:false, match words:false, extend selection:false}
		replace "-" using "–" searching in text 1 of text window 1 options {search mode:literal, starting at top:true, wrap around:false, backwards:false, case sensitive:false, match words:false, extend selection:false}
		replace "\\t" using "," searching in text 1 of text window 1 options {search mode:literal, starting at top:true, wrap around:false, backwards:false, case sensitive:false, match words:false, extend selection:false}
		replace ",NAME" using "POS,NAME" searching in text 1 of text window 1 options {search mode:literal, starting at top:true, wrap around:false, backwards:false, case sensitive:false, match words:false, extend selection:false}
		replace "0 " using "0," searching in text 1 of text window 1 options {search mode:literal, starting at top:true, wrap around:false, backwards:false, case sensitive:false, match words:false, extend selection:false}
		replace "1 " using "1," searching in text 1 of text window 1 options {search mode:literal, starting at top:true, wrap around:false, backwards:false, case sensitive:false, match words:false, extend selection:false}
		replace "2 " using "2," searching in text 1 of text window 1 options {search mode:literal, starting at top:true, wrap around:false, backwards:false, case sensitive:false, match words:false, extend selection:false}
		replace "3 " using "3," searching in text 1 of text window 1 options {search mode:literal, starting at top:true, wrap around:false, backwards:false, case sensitive:false, match words:false, extend selection:false}
		replace "4 " using "4," searching in text 1 of text window 1 options {search mode:literal, starting at top:true, wrap around:false, backwards:false, case sensitive:false, match words:false, extend selection:false}
		replace "5 " using "5," searching in text 1 of text window 1 options {search mode:literal, starting at top:true, wrap around:false, backwards:false, case sensitive:false, match words:false, extend selection:false}
		replace "6 " using "6," searching in text 1 of text window 1 options {search mode:literal, starting at top:true, wrap around:false, backwards:false, case sensitive:false, match words:false, extend selection:false}
		replace "7 " using "7," searching in text 1 of text window 1 options {search mode:literal, starting at top:true, wrap around:false, backwards:false, case sensitive:false, match words:false, extend selection:false}
		replace "8 " using "8," searching in text 1 of text window 1 options {search mode:literal, starting at top:true, wrap around:false, backwards:false, case sensitive:false, match words:false, extend selection:false}
		replace "9 " using "9," searching in text 1 of text window 1 options {search mode:literal, starting at top:true, wrap around:false, backwards:false, case sensitive:false, match words:false, extend selection:false}
		replace " 0" using ",0" searching in text 1 of text window 1 options {search mode:literal, starting at top:true, wrap around:false, backwards:false, case sensitive:false, match words:false, extend selection:false}
		replace " 1" using ",1" searching in text 1 of text window 1 options {search mode:literal, starting at top:true, wrap around:false, backwards:false, case sensitive:false, match words:false, extend selection:false}
		replace " 2" using ",2" searching in text 1 of text window 1 options {search mode:literal, starting at top:true, wrap around:false, backwards:false, case sensitive:false, match words:false, extend selection:false}
		replace " 3" using ",3" searching in text 1 of text window 1 options {search mode:literal, starting at top:true, wrap around:false, backwards:false, case sensitive:false, match words:false, extend selection:false}
		replace " 4" using ",4" searching in text 1 of text window 1 options {search mode:literal, starting at top:true, wrap around:false, backwards:false, case sensitive:false, match words:false, extend selection:false}
		replace " 5" using ",5" searching in text 1 of text window 1 options {search mode:literal, starting at top:true, wrap around:false, backwards:false, case sensitive:false, match words:false, extend selection:false}
		replace " 6" using ",6" searching in text 1 of text window 1 options {search mode:literal, starting at top:true, wrap around:false, backwards:false, case sensitive:false, match words:false, extend selection:false}
		replace " 7" using ",7" searching in text 1 of text window 1 options {search mode:literal, starting at top:true, wrap around:false, backwards:false, case sensitive:false, match words:false, extend selection:false}
		replace " 8" using ",8" searching in text 1 of text window 1 options {search mode:literal, starting at top:true, wrap around:false, backwards:false, case sensitive:false, match words:false, extend selection:false}
		replace " 9" using ",9" searching in text 1 of text window 1 options {search mode:literal, starting at top:true, wrap around:false, backwards:false, case sensitive:false, match words:false, extend selection:false}
		
		save text window 1 to alias (var_FileName & ".csv")
		
		close text window 1
		
	end tell
	
end open

Thanks again

The fastest way would of course be using AppleScript’s text item delimiters, but they replace all characters. Maybe a Perl script can help you?

substituteStringAtIndex("Hello, how are you?", space, " ¢STRING REPLACED¢ ", 2)

on substituteStringAtIndex(sourceStr, torep, repment, n)
	set myShell to "/usr/bin/perl -e \"" & ¬
		"\\$toReplace = " & quoted form of torep & ";" & ¬
		"\\$replacement = " & quoted form of repment & ";" & ¬
		"\\$n = " & n & ";" & ¬
		"\\$text = " & quoted form of sourceStr & ";" & ¬
		"\\$regexp = \\\"((?:[^\\\" . \\$toReplace . \\\"]*\\\" . \\$toReplace . \\\"[^\\\" . \\$toReplace . \\\"]*){\\\" . (\\$n-1) . \\\"})\\\" . \\$toReplace;" & ¬
		"\\$text =~ s/\\$regexp/\\$1\\$replacement/;" & ¬
		"print \\\"\\$text\\\";\""
	
	--set the clipboard to myShell --debug
	
	return do shell script myShell
end substituteStringAtIndex

This is the original Perl script: a little bit more readable.

Hope it helps,
ief2

Hi,

this is a simple handler using text item delimiters


replaceNthOccurrenceOfString("65,O'Flaherty; Thomas Jamestown Jaguars 743,92,42", space, ",", 2)

on replaceNthOccurrenceOfString(theText, findString, replaceString, occurrence)
	set {TID, text item delimiters} to {text item delimiters, findString}
	set textItems to text items of theText
	set text item delimiters to TID
	set cnt to count textItems
	if cnt = 0 or occurrence ≥ cnt then return theText
	return (items 1 thru (occurrence) of textItems as text) & replaceString & items (occurrence + 1) thru -1 of textItems as text
end replaceNthOccurrenceOfString

Hi, Stefan.

The TIDs should be restored after the lists have been coerced back to text. :slight_smile:

It’s also possible to dispense with the lists altogether:


replaceNthOccurrenceOfString("65,O'Flaherty; Thomas Jamestown Jaguars 743,92,42", space, ",", 2)

on replaceNthOccurrenceOfString(theText, findString, replaceString, occurrence)
	set {TID, text item delimiters} to {text item delimiters, findString}
	set cnt to (count theText each text item)
	if (cnt = 0) or (occurrence ≥ cnt) then
		set output to theText
	else
		set output to text 1 thru text item occurrence of theText & replaceString & text from text item (occurrence + 1) to -1 of theText		
	end if
	set text item delimiters to TID
	
	return output
end replaceNthOccurrenceOfString

of course, thanks.

I know that, but I forget it always :wink:

Thank you for all your input. Do you have any advice or pointers as to how I go about integrating the solutions you have proposed into my existing script?

I tried adding the code (- you can tell I’m a newbie at this sort of thing!) after the last replace line in my existing code but ended up with errors. I think this is because:

  1. The scripts have nothing to do with TextWrangler, possibly,
  2. I need to save the contents of text 1 of text window 1 and end the tell to TextWrangler, I think.
  3. Reopen the text file in Applescript.
  4. Load the text.
  5. Setup a loop for the text to be read and processed line by line using the script(s) you provided.
  6. Save the changed text contents.
  7. End the tell to the script provided.

Am I on the right track here? If so, do you have any idea where I can find examples/step-throughs of this kind of thing?

Lastly, I realised that my existing script was long-winded and tried to do something about it by replacing:

with this:

However, this only partially worked as what I end up with is:

i.e. the revised code fails to replace the space after the number before the start of the name with a comma.
Can anyone explain to me why this is happening?

Also, I was wondering if it is possible to reduce the code for the following section by introducing a loop until there are no more double tabs found:

Thank you again for your help. :slight_smile: