Change spaces in theResult url?

Hi,

I’m trying to extend a script I’m using. It now breaks the url when there’s a space in the filepath.

Whats I now get is:
https://download.url.com/folder1/best practises

Whats I need is:
https://download.url.com/folder1/best%20practises

return expand("")

on ReplaceText(theString, fString, rString)
	set current_Delimiters to text item delimiters of AppleScript
	set AppleScript's text item delimiters to fString
	set sList to every text item of theString
	set AppleScript's text item delimiters to rString
	set newString to sList as string
	set AppleScript's text item delimiters to current_Delimiters
	return newString
end ReplaceText

on expand(separator)
	
	tell application "Finder"
		set theSelection to get selection as list
		set theResult to ""
		if length of separator = 0 then set separator to linefeed
		repeat with theItem in theSelection
			if length of theResult > 0 then set theResult to theResult & separator
			set theResult to theResult & POSIX path of (theItem as alias)
			set theResult to ReplaceText(theResult, "/Volumes/DISK_A", "https://download.url.com") of me
		end repeat
		return theResult
	end tell
	
end expand

I found a script here, but it is not clear how to add this to the script above and if this is the right one?

replaceChars("/Volumes/A Hard Drive", space, "%20")

on replaceChars(aString, charToReplace, newChar)
   set {TID, text item delimiters} to {text item delimiters, charToReplace}
   set aString to text items of aString
   set text item delimiters to newChar
   set aString to aString as text
   set text item delimiters to TID
   return aString
end replaceChars

Anybody here how to implement this?

Thanks.

Vanwoods. The ReplaceText and replaceChars handlers are functionally the same, and both work for me. Just as a matter of personal preference, I would use the replaceChars handler. However, I don’t understand their use in the expand handler. Instead of line 1 below shouldn’t it be line 2 below. I don’t understand the purpose of the expand handler, so perhaps there’s some reason for this?

set theResult to ReplaceText(theResult, "/Volumes/DISK_A", "https://download.url.com") of me
set theResult to ReplaceText(theResult, space, "%20") of me

Hi peavine,

Thanks for getting back to me!

It’s in an expand handler because I use it for text expansion in email. We are selecting the file in the finder and then expand the script when typing a text string. It gives a download link which can be send to the client.

The below script works now but I don’t know if this is the best setup. To copy the line multiple times?

return expand("")

on ReplaceText(theString, fString, rString)
   set current_Delimiters to text item delimiters of AppleScript
   set AppleScript's text item delimiters to fString
   set sList to every text item of theString
   set AppleScript's text item delimiters to rString
   set newString to sList as string
   set AppleScript's text item delimiters to current_Delimiters
   return newString
end ReplaceText

on expand(separator)
   
   tell application "Finder"
       set theSelection to get selection as list
       set theResult to ""
       if length of separator = 0 then set separator to linefeed
       repeat with theItem in theSelection
           if length of theResult > 0 then set theResult to theResult & separator
           set theResult to theResult & POSIX path of (theItem as alias)
           set theResult to ReplaceText(theResult, "/Volumes/DISK_A", "https://download.url.com") of me
           set theResult to ReplaceText(theResult, space, "%20") of me
           set theResult to ReplaceText(theResult, "/Volumes/DISK_B", "https://download.url.com") of me
           set theResult to ReplaceText(theResult, space, "%20") of me
           set theResult to ReplaceText(theResult, "/Volumes/DISK_C", "https://download.url.com") of me
           set theResult to ReplaceText(theResult, space, "%20") of me
       end repeat
       return theResult
   end tell
   
end expand

Thanks for getting back. I tried to combine the above script with my version but I couldn’t get it to work. Is this approach better than what I have?

A s in the previous post it’s now working as what I needed, just wondered if this was the best way?

Thanks for your help!!

Here is a slightly cleaned up version
I moved most of the routine ‘expand’ outside of the tell “Finder” block.

return expand("")

on ReplaceText(theString, fString, rString)
	local tid, newString
	set tid to text item delimiters
	set text item delimiters to fString
	set sList to every text item of theString
	set text item delimiters to rString
	set newString to sList as string
	set text item delimiters to tid
	return newString
end ReplaceText

on expand(separator)
	local tid, theSelection, theResult
	set tid to text item delimiters
	tell application "Finder" to set theSelection to selection
	if length of separator = 0 then set separator to linefeed
	repeat with theItem in theSelection
		set contents of theItem to POSIX path of (theItem as alias)
	end repeat
	set text item delimiters to linefeed
	-- uncomment end of line below to have trailing linefeed
	set theResult to (theSelection as text) -- & linefeed
	set theResult to ReplaceText(theResult, "/Volumes/DISK_A", "https://download.url.com")
	set theResult to ReplaceText(theResult, "/Volumes/DISK_B", "https://download.url.com")
	set theResult to ReplaceText(theResult, "/Volumes/DISK_C", "https://download.url.com")
	set theResult to ReplaceText(theResult, space, "%20") -- only needs to be done once
	set text item delimiters to tid
	return theResult
end expand

And here is another one with using URL property of selection.
It makes it so we don’t have to replace spaces with %20

return expand("")

on ReplaceText(theString, fString, rString)
	local tid, newString
	set tid to text item delimiters
	set text item delimiters to fString
	set sList to every text item of theString
	set text item delimiters to rString
	set newString to sList as string
	set text item delimiters to tid
	return newString
end ReplaceText

on expand(separator)
	local tid, theSelection, theResult
	set tid to text item delimiters
	if length of separator = 0 then set separator to linefeed
	tell application "Finder"
		set theSelection to selection
		repeat with theItem in theSelection
			set contents of theItem to URL of theItem
		end repeat
	end tell
	set text item delimiters to linefeed
	-- uncomment end of line below to have trailing linefeed
	set theResult to (theSelection as text) -- & linefeed
	set theResult to ReplaceText(theResult, "file:///Volumes/", "https://download.url.com/")
	set text item delimiters to tid
	return theResult
end expand

The process of replacing special characters in a URL string is called URL encoding. In my experience, AsObjC and ruby handle this most successfully and consistently. The correct AsObjC-handler provided by @Fredrik71 above.

I prefer the ruby solution in cases where AsObjC is not needed by the rest of the script. Because bootstrapping the AsObjC frameworks kills. Note: I commented taking the finder selection and hardcoded the selected file in my example. You can use commented code line instead.


-- tell application "Finder" to set posixPath to POSIX path of ((item 1 of (get selection)) as text)
set posixPath to "/Volumes/DISK_A/folder1/best practises"

set newPath to ReplaceText(posixPath, "/Volumes/DISK_A/", "https://download.url.com/")
set theURL to encodeURL_ruby(newPath)


on ReplaceText(theString, fString, rString)
	set current_Delimiters to text item delimiters of AppleScript
	set AppleScript's text item delimiters to fString
	set sList to every text item of theString
	set AppleScript's text item delimiters to rString
	set newString to sList as string
	set AppleScript's text item delimiters to current_Delimiters
	return newString
end ReplaceText


on encodeURL_ruby(theURL)
	do shell script "ruby -e 'require \"uri\";puts URI.escape(\"" & theURL & "\")'"
end encodeURL_ruby

If you do not take into account the bootstrap time of frameworks, then the AsObjC solution is the fastest of all. The second fastest is the perl solution.

I did not include it from the very beginning only because it also encodes the characters “:” and “/”, and as I understand it, the OP do not want this. Although it is this URL encoding that is the standard.


set posixPath to "/Volumes/DISK_A/folder1/best practises"

set newPath to ReplaceText(posixPath, "/Volumes/DISK_A/", "https://download.url.com/")
set theURL to encodeURL_perl(newPath)


on ReplaceText(theString, fString, rString)
	set current_Delimiters to text item delimiters of AppleScript
	set AppleScript's text item delimiters to fString
	set sList to every text item of theString
	set AppleScript's text item delimiters to rString
	set newString to sList as string
	set AppleScript's text item delimiters to current_Delimiters
	return newString
end ReplaceText


on encodeURL_perl(theURL) -- the fastest Plain AppleScript method
	do shell script "/usr/bin/perl -e 'use URI::Escape; print uri_escape(\"" & theURL & "\")';"
end encodeURL_perl

Here is very nice AppleScript-solution which doesn’t use shell commands and AsObjC frameworks at all. It is very very fast and allows user defined character sets to encode (see standard_characters, URL_A_chars and URL_A_chars lists in the handler).

You can see the the symbol “:” in URL_B_chars and symbol “/” in URL_A_chars. So, I put to not encode both lists when calling the handler (parameters false, false).


set posixPath to "/Volumes/DISK_A/folder1/best practises"
set newPath to ReplaceText(posixPath, "/Volumes/DISK_A/", "https://download.url.com/")

encode_text(newPath, false, false)

on ReplaceText(theString, fString, rString)
	set current_Delimiters to text item delimiters of AppleScript
	set AppleScript's text item delimiters to fString
	set sList to every text item of theString
	set AppleScript's text item delimiters to rString
	set newString to sList as string
	set AppleScript's text item delimiters to current_Delimiters
	return newString
end ReplaceText

on encode_text(this_text, encode_URL_A, encode_URL_B)
	set the standard_characters to "abcdefghijklmnopqrstuvwxyz0123456789"
	set the URL_A_chars to "$+!'/?;&@=#%><{}[]\"~`^\\|*"
	set the URL_B_chars to ".-_:"
	set the acceptable_characters to the standard_characters
	if encode_URL_A is false then set the acceptable_characters to the acceptable_characters & the URL_A_chars
	if encode_URL_B is false then set the acceptable_characters to the acceptable_characters & the URL_B_chars
	set the encoded_text to ""
	repeat with this_char in this_text
		if this_char is in the acceptable_characters then
			set the encoded_text to (the encoded_text & this_char)
		else
			set the encoded_text to (the encoded_text & encode_char(this_char)) as string
		end if
	end repeat
	return the encoded_text
end encode_text

on encode_char(this_char)
	set the ASCII_num to (the ASCII number this_char)
	set the hex_list to {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"}
	set x to item ((ASCII_num div 16) + 1) of the hex_list
	set y to item ((ASCII_num mod 16) + 1) of the hex_list
	return ("%" & x & y) as string
end encode_char

Finally, I should note that the original problem can be solved even more efficiently. To do this, you need to use the fact that the Finder itself provides the URL-encoded form “file:///”. You just need to stupidly replace “file:///” with “https://”. :wink:


set URLs to {}
tell application "Finder"
	repeat with anItem in (get selection)
		set end of URLs to my replaceText(URL of anItem, "file:///", "https://")
	end repeat
end tell
return URLs

on replaceText(theString, fString, rString)
	set ATID to text item delimiters of AppleScript
	set AppleScript's text item delimiters to fString
	set sList to text items of theString
	set AppleScript's text item delimiters to rString
	set newString to sList as text
	set AppleScript's text item delimiters to ATID
	return newString
end replaceText

Thanks, I tried al the above scripts and they work like a charm!

Only one more question, is it possible to have to the second part after /VOLUMES/DISK_A or DISK_B or DISK_C be replaced no matter how the disk (or share) is called? Copying the lines like below is resulting in normal posixPaths and not the url (https://download.url.com/)

set newPath to ReplaceText(posixPath, "/Volumes/DISK_A/", "https://download.url.com/")
set newPath to ReplaceText(posixPath, "/Volumes/DISK_B/", "https://download.url.com/")
set newPath to ReplaceText(posixPath, "/Volumes/DISK_C/", "https://download.url.com/")