AppleScript: remove last character in text string - applescript

I need to remove the last character in a text string AppleScript. It's proving to the much more difficult problem than I thought.
can someone explain how this would be done?

Try this
set t to "this is a string"
text 1 thru -2 of t
Output:
"this is a strin"

Sympathies. It ought to be a trivial task (in most languages it's just a matter of calling a built-in "trim" function) but AppleScript has absolutely miserable library support and the community has done nothing to plug these gaps itself, so you have to roll your own ad-hoc handlers for even basic everyday stuff like this. For example:
on trimLastChar(theText)
if length of theText = 0 then
error "Can't trim empty text." number -1728
else if length of theText = 1 then
return ""
else
return text 1 thru -2 of theText
end if
end trimLastChar
You might consider investing in an AppleScript book (note: I co-wrote the Apress one), which tend to cover common text and list processing tasks much better than AppleScript's own documentation.
Another option is to call through to Cocoa via the AppleScript-ObjC bridge, giving you free access to a huge amount of ready-to-use functionality. It's a bit more work, but for more advanced text processing tasks it's often the simplest, safest, and most efficient solution. I recommend getting a copy of Shane Stanley's Everyday AppleScript-ObjC if/when you go that way.

tell application "Safari"
open location "https://www.youtube.com/watch?v=IxnD5AViu6k#t=152.07430805"
delay 1
end tell
delay 1
tell application "Safari"
set theURL to URL of front document as text
end tell
if theURL contains "#" then
repeat until theURL does not contain "#"
set theURL to text 1 thru -2 of theURL
end repeat
end if

I find this to be interesting http://applehelpwriter.com/2016/09/06/applescript-remove-characters-from-a-string/
Essentially, you can import Foundation to help you
use scripting additions
use framework "Foundation"
property NSString : a reference to current application's NSString
Here is how I remove the last path component
on myRemoveLastPath(myPath)
set myString to NSString's stringWithString:myPath
set removedLastPathString to myString's stringByDeletingLastPathComponent
removedLastPathString as text
end myRemoveLastPath

Related

Applescript find, replace and style

I've been trying to get this simple script to work, it's supposed to search for a string, replace it while applying some styling, e.g. setting the text bold and red.
Here's what I have so far:
tell application "Finder"
set fl to files of folder POSIX file "/Users/Sc/Desktop/app/" as alias list
end tell
repeat with f in fl
tell application "TextEdit"
open f
set text of front document to replace_chars(text of front document, "a", "0000") of me
end tell
end repeat
on replace_chars(this_text, search_string, replacement_string)
set AppleScript's text item delimiters to the search_string
set the item_list to every text item of this_text
set the size of replacement_string to 14
set AppleScript's text item delimiters to the replacement_string
set this_text to the item_list as string
set AppleScript's text item delimiters to ""
return this_text
end replace_chars
However this produces an error, I understand why, but not sure how to go about styling it before replacement, any help would be appreciated.
TextEdit uses Cocoa Scripting's standard Text Suite implementation, which is pretty naff at the best of times. If you're doing whole-word replacement, the following should work:
tell application "TextEdit"
set aRef to a reference to (every word of document 1 where it is "OLDWORD")
set aRef's color to {65535, 0, 0}
set aRef's contents to "NEWWORD"
end tell
The same approach should also work for single-character or whole-paragraph replacement; just modify the every word of... query appropriately. In each case though, you must match exactly one word/character/paragraph and replace it with exactly one word/character/paragraph, otherwise you'll get hilarious off-by-N errors throughout subsequent matches[1] due to Cocoa Scripting being made of dumb and incompetent[2] (e.g. try changing a recurring word to two new words, e.g. "foo" -> "boo boo" to see what I mean).
Also, unlike Text Suite implementations found in better written apps, Cocoa Scripting's Text Suite provides no way to describe to text ranges (e.g. text (character i) thru (character j) of.../text i thru j of...), so it's impossible to tell TextEdit to match, say, "oo" in "baboon", "fool", "spitoon", etc. If you need to match arbitrary character ranges, you'll have to get the text into AppleScript and calculate the start and end of each match yourself.
[1] When making multiple replacements, CS's Text Suite first calculates the positions of all of the text ranges that need changed, and then performs each substitution starting at the first match and finishing at the last. Thus, any differences in the length of the new vs old text mean all of the remaining match indexes it already calculated are no longer correct because the characters previously at that position have now shifted to the left or right. To do the job right, CS should've calculated all the positions from first to last, and then replaced them starting at the last and working backwards to the first.
[2] (CocoaScripting.framework was originally designed by Cocoa developers who didn't understand how AppleScript works, and since then has been maintained by AppleScript developers who don't understand either. So it goes.)
TextEdit is not the best tool to search and replace styled text, for example the free TextWrangler has more powerful skills to do that.
Anyway, try this, it affects only one opened document in TextEdit
The "algorithm" is to calculate the offset of the search string, replace it with the replace string and keeps the location in a repeat loop. At the end reassign the changed text to the text object of TextEdit and change the style at the stored locations to {font: Helvetica Bold, size: 24 and color: red}.
property searchString : "a"
property replaceString : "0000"
tell application "TextEdit"
set completed to false
set ranges to {}
set theText to text of front document
set theSize to size of text of front document
repeat while completed is false
tell current application to set o to offset of searchString in theText
if o is 0 then
set completed to true
else
tell theText to set newText to text 1 thru (o - 1) & replaceString & text (o + (length of searchString)) thru -1
set end of ranges to o
copy newText to theText
end if
end repeat
set text of front document to theText
set size of text of front document to theSize
repeat with aRange in ranges
tell characters aRange thru (aRange + (length of replaceString) - 1) of front document
set size to 24
set its color to {65535, 0, 0}
set font to "Helvetica Bold"
end tell
end repeat
end tell
Since the other posters both noted how poorly suited TextEdit is for this task, allow me to make an "out of the box" suggestion: Use MS Word
The Find and Replace tool in Word can easily handle this task, and much more complicated replacements.
If you have a lot of source documents in RTF format, you could open them in Word, make the changes, and save back to the same (or different) RTF file. It would be very easy to create a Word VBA macro to do this.
You could then either write an AppleScript to open each RTF file in Word and run the macro, or you could do all of the processing using a master Word VBA. You could do it in either way, but I would choose the all VBA route since, IMO, it is a much better language for processing MS documents than AppleScript.
Of course, this requires that you have MS Word installed. I'm still running MS Office 2011 on all of my Macs, and don't plan to upgrade to Office 2016 for a while. Word 2011 works very well.
Good luck.

Change the color of text by using applescript

I am writing some text in to word file i want to change the color of that text any one can help on that one plz.
I want to print the 'message' from following script in red color.
Here is the Script:
set message to "mostly these windows are popup in application"
on ResultCreationFuction(message)
try
set text_to_save to message as text
tell application "System Events"
tell application "Finder"
set sortedList to sort (get files of folder "SofTestAutomationResult" of desktop) by modification date
set FileCount to get count of sortedList
set theFile to (item FileCount of sortedList) as alias
end tell
set file_ref to open for access theFile with write permission
write (text_to_save & return) to the file_ref starting at eof
close access file_ref
delay 2
end tell
end try
end ResultCreationFuction
Some Details:
The file is word which is all ready present on above location having name "10.012.2014_17_4_20.doc" (the name of .doc file is not fix)
What you are attempting is the wrong way to do it.
To manipulate content like that, including formatted text (not plain
text), you need to work within, ideally, a well-scriptable app, like
Pages (or Word, perhaps, but I don't have that on the machine I'm
writing this from).
Don't use System Events if you don't need to. Use the apps with the appropriate AppleEvents/dictionary, etc. If you don't know what I'm talking about, you need to take advantage of the infinite resource known as the web.
"Fuction" is just bad form.
I would suggest doing a lot more reading up on how AppleScript works (or scripting in general), but to start you out, here is a script I just wrote in pages which sets the color of a specific word of the open document after putting text in there:
tell application "Pages"
set body text of document 1 to "hello there mister fancy pants"
set color of word 3 of body text of page 1 of document 1 to {64614, 0, 111}
end tell
If you have Pages, try this by starting with a blank page and running this script. Obviously, you could get rid of "word 3 of" in the 2nd line, and the whole body text will be red.
I hope this makes sense and is of help.
[edit]
I should mention that even TextEdit is scriptable and can open Word documents. Here's an example using TextEdit:
tell application "TextEdit"
set text of document 1 to "hello mister fancy pants"
set color of words 2 thru 3 of text of document 1 to {65535, 0, 0}
end tell
There is a little danger of non-Word apps losing formatting of Word files. But it just seems you are attempting something very simple, and I'm not sure if Word is really necessary here.
You can't add color using the write to eof. You should open the document in Word and then insert the line and add the color. Here's a script that should demonstrate how:
set text_to_add to "mostly these windows are popup in application"
set theFile to ((path to desktop folder) & "10.012.2014_17_4_20.doc") as string
tell application "Microsoft Word"
set theFile to theFile as string -- assuming theFile is an alias or :: path
open file theFile
tell active document
set endOfDoc to end of content of text object -- insert the text to end of document
set theRange to create range start (endOfDoc - 1) end endOfDoc
insert text text_to_add at theRange
set myRange to create range start endOfDoc end (endOfDoc + (length of text_to_add))
set color index of font object of myRange to red
save
end tell
end tell

AppleScript to get the active list in Reminders?

Can anyone help me to get the active list on display in the Reminders app on OS X?
According to the applescript dictionary for reminders, the application has a "default list" property which is "the list currently active in the Reminders application."
However, this property always seems to return the first list in order in the lists sidebar, not the list which is actually being displayed and is active. I have found that if I rearrange the order of the lists in the sidebar, I will always get whichever I have made the first list, regardless of which is actually being viewed and worked with.
My application is to create a Keyboard Maestro trigger to run an AppleScript to print the list I am currently working on, but it does not appear that the Reminders app functions as is documented in its dictionary. (I have temporarily used a workaround of having the script pop up a chooser listing all the lists so I can select the one i want to print, but that's inefficient and inelegant).
Thanks!
Yes, you can, but you will have to use the bad GUI scripting. And in a bad way. Look:
--Do some GUI scripting to get the decription of a specific group
tell application "Reminders" to activate
tell application "System Events"
tell process "Reminders"
tell window "Reminders"
tell splitter group 1
tell group 1
set des to get description
end tell
end tell
end tell
end tell
end tell
--This description is in the format "Viewing MyList, 1 reminder" so get the part to the "," from des.
set text item delimiters to ","
set texitems to text items of des
set firstPart to get text item 1 of texitems
--Setting the delimiters back
set text item delimiters to ""
--Jump to charcter 9 of firstPart then converting to text
set listname to characters 9 thru end of firstPart as text
--Now we know the name of the current list, so do whatever you want:
tell application "Reminders" to get list listname
This works. But only if Reminders is open. And if Apple changes Reminders structure...

AppleScript inserts string into application inbetween double quotes

I just purchased Alfred App for my Mac and I want to use this script I found online:
---------------------------------------------------
--Modified by: Pontus Sundén, http://psu.se
--Icon from: http://findicons.com/pack/1362/private_eye_act_1
---------------------------------------------------
on alfred_script(strQuery)
--Get the parameters passed to the script - this is the search query
set strSearchCriteria to SpaceList(strQuery)
--Try to populated an existing window with the search query
tell application "Evernote"
try
set query string of window 1 to strSearchCriteria
on error
--No existing window, open an new one
open collection window with query string strSearchCriteria
end try
end tell
tell application "System Events" to set frontmost of process "Evernote" to true
end alfred_script
--Take a list of text items and retrun them as a string with a space between each item
on SpaceList(astrItems)
--Store what the current list delimiter is
set tmpDelimiters to AppleScript's text item delimiters
--Set the list delimiter to a space and build the string we want to pass back
set AppleScript's text item delimiters to " "
set strReturn to astrItems as string
--Set the list delimiter back to what it was previously
set AppleScript's text item delimiters to tmpDelimiters
--Return the string we built
return strReturn
end SpaceList
which should open up evernote and search for something. It works fine, but instead of searching for, say the word boat, it will search for "boat" with the double quotes and obviously this yields no matches.
Your script is perfectly correct – the spurious quoting of search terms passed via AppleScript is a known Evernote bug in version 3 of the client (well, “known” as in “I opened a support ticket for it a while ago, and Evernote acknowledged it”; I’d add a link to the ticket, but these are private to the user who opened it … will update on progress, though).
Until they get around to fix it, you will have to either use the suggested GUI Scripting solution as a workaround, or correct the search strings manually.
You can use UI scripting to populate the search field like this:
set xxx to "boat"
activate application "Evernote"
tell application "System Events" to tell process "Evernote"
set value of text field 1 of group 4 of tool bar 1 of window 1 to xxx
end tell

Get message in compose window from Mail.app

I am trying to make a script that will get the contents of an email message that I'm composing in Mail, do something with the data, and then send the message. I know how to make and send a new message from scratch with AppleScript, but I can't find a way to get a message that I'm already writing. I don't care what language is used, and I would be open to trying a different email client. Thanks for your help!
Mail has huge limitations with regards to Applescript and dealing with its content area is a major one. The best bet is to use GUI scripting to tab to the content area, type cmd-C, and then work off the data in the clipboard.
Sadly from what I can see Applescript has not been improved at all in Lion.
It's actually pretty easy to do what you need.
If you want to run some kind of an inline processing (assigned to, say, a hotkey (in Mail, e.g. Cmd+D is not occupied), or "just" listed in the Services menu, accessible after selecting something), you can simply use Automator. A demo Automator script reading the current selection, making some changes (here, converting some ASCII char+number combinations to some accented characters) and, finally, returning the modified text is as follows:
on run {input, parameters}
set myText to replaceText("a1", "á", (input as text))
set myText to replaceText("e1", "é", myText)
set myText to replaceText("i1", "í", myText)
return myText
end run
on replaceText(find, replace, someText)
set prevTIDs to text item delimiters of AppleScript
set text item delimiters of AppleScript to find
set someText to text items of someText
set text item delimiters of AppleScript to replace
set someText to "" & someText
set text item delimiters of AppleScript to prevTIDs
return someText
end replaceText
Make sure you enable the "Replaces selected text", should you want to overwrite the original content with the returned one.
if you want to write an external script not invoked from the local Services menu (or via a hotkey), you'll also need to add clipboard handling. A solution similar to the above with additional clipboard copy/paste:
on replaceText(find, replace, someText)
set prevTIDs to text item delimiters of AppleScript
set text item delimiters of AppleScript to find
set someText to text items of someText
set text item delimiters of AppleScript to replace
set someText to "" & someText
set text item delimiters of AppleScript to prevTIDs
return someText
end replaceText
tell application "Mail"
activate
tell application "System Events"
tell process "Mail"
click menu item "Select All" of menu "Edit" of menu bar 1
click menu item "Copy" of menu "Edit" of menu bar 1
end tell
end tell
end tell
tell application "Mail"
set textclip to (the clipboard)
end tell
set myText to replaceText("a1", "á", textclip)
set myText to replaceText("e1", "é", myText)
set myText to replaceText("i1", "í", myText)
set the clipboard to myText
tell application "Mail"
activate
tell application "System Events"
tell process "Mail"
click menu item "Paste" of menu "Edit" of menu bar 1
end tell
end tell
end tell
Note that the latter script selects (and, then, overwrites) the entire window contents. It should be easy to work on the current selection only.
It's possible, but painful. Painful enough that I'm still trying to work out exactly how to do something similar but in Safari. I've gotten to the point where I can find the textarea, but the documentation I've found for getting the content isn't working. (Unfortunately, that's pretty much par for the course for AppleScript; every program does stuff just a little bit differently from the next program.)
EDIT: ok, have some horrible evil which hopefully can be adapted to work with Mail: http://www.ece.cmu.edu/~allbery/edit_textarea.script
This is striaghtforward if we make two reasonably weak assumptions: that the message you're working on is frontmost, and that the subject of all draft messages is unique. Then, before running the script, save the message you're working on; this will place it in the drafts mailbox. Then, since the subject of the message is the name of the window, we can easily access it; and since we can easily access the drafts mailbox, we can combine the two. This gives us:
tell application "Mail"
set msgs to messages of drafts mailbox ¬
whose subject is (name of window 1 as string)
if (count of msgs) = 1 then
-- Do whatever
else
-- Error, disambiguate, whatever
end if
end tell
It's probably possible to make the script save the frontmost window, and it wouldn't surprise me if a freshly-saved message is always the first item of the drafts mailbox, but these are left as an exercise for the reader :-)
So I came across this in 2020 and with this Apple Script it is (now?) possible (whenever its still a bit hacky since I have to use the clipboard for this):
activate application "Mail"
tell application "System Events"
tell process "Mail"
set initialClipboardContent to (the clipboard as text)
set composeWindow to (first window whose title does not contain "Inbox")
set value of attribute "AXFocused" of UI element 1 of scroll area 1 of composeWindow to true
delay 0.05
# CMD + A
key code 0 using command down
delay 0.1
# CMD + C
key code 8 using command down
delay 0.1
set message to (the clipboard as text) as string
log message
set the clipboard to initialClipboardContent
end tell
end tell
Here a proof of concept:

Resources