-
Is it possible to copy the contents of a variable to the clipboard? Specifically a value. Or WRITE the value of a variable to a field. WRITE gives me an error that I am missing a parameter.
-
looking for a way to convert text files stored in high ascii, into low ascii.
-
I can do KEYSTROKE RETURN, but can’t do KEYSTROKE DELETE or KEYSTROKE BACKSPACE. Is there an alternative
IamRob. The following works with my keyboard:
tell application "System Events" to tell process "TextEdit"
set frontmost to true
key code 51 -- back delete
-- key code 117 -- forward delete
end tell
BTW, I’m not aware of a corresponding equivalent for the above to keystroke return.
set someValue to "xyz"
set the clipboard to someValue
Not sure what you mean by a ‘field’.
Thanks for the replies.
-
key code 51 works perfectly, thanks.
-
set the clipboard to var – at least does not give me an error now, but the PASTE function goes dim. Meaning, if there was something in the clipboard and the menu item “PASTE” was previously selectable, now is no longer selectable.
Is “the clipboard” under a different process other than the application that is currently running?
In TextEdit, pressing Command-L gives a “goto line number” option. I thought I read in another post the rectangular entry box was called a field. I would like to either “paste” the value from the variable into that entry box, or “write” the value of the variable into the entry box.
solved number 1)
set var to 261
set the clipboard to var as text
I see very little posts on the clipboard, but it is starting to turn out to be a powerful tool. Can now do:
set v1 to the clipboard as text
set v2 to v1 + 3
return v2
or
set v1 to the clipboard as text
set v2 to v1 & “3”
return v2
Should now be able to step 2) on my own, but does anyone have an example of, or know what “WRITE” does?
Where are you getting “WRITE” from in this context? The write command is part of Standard Additions’ File Read/Write Suite (see below), and not part of TextEdit’s rather limited scripting dictionary. It won’t help you filling dialog boxes.
You could try playing with the following:
set the clipboard to "9"
tell application "TextEdit" to activate
delay 1
tell application "System Events"
keystroke "l" using command down
keystroke "v" using command down
keystroke return
end tell
(Apps must be activated to access the system clipboard.)
This activates TextEdit, displays the go-to-line dialog box, pastes in the contents of the clipboard and then confirms the dialog by simulating a return. The first two keystroke commands must use lowercase letters. It doesn’t trap any potential errors (alpha characters in the clipboard, invalid line numbers…).
But it’s pretty clunky. Generally speaking, using AppleScript to manipulate interface elements (pasting, dialog boxes etc) is a bit of a last resort.
For example, the following modifies paragraph 9 of the frontmostTextEdit document without involving any interface elements:
set myPar to 9
set myText to "something different " & return
tell application "TextEdit"
activate
tell document 1
set paragraph myPar to myText
end tell
end tell
It’s quicker, more flexible and more powerful.
Couple of thoughts:
If you need to process text with AppleScript, you might want to investigate a more powerful scriptable text editor (BBEdit is probably the tool of choice, CotEditor is an alternative).
And as mentioned above, AppleScript has its own basic file read/write capabilities, with which it can read, edit and save text files without opening them in the user interface.
Here’s a very very quick example of the write command in Standard Additions:
set filePath to (path to desktop as string) & "demo.txt"
set nuText to (open for access file filePath with write permission)
write "This is a demo" to nuText
close access nuText
This creates a file on the user’s desktop called demo.txt, opens it, writes some text to it, and closes it off. Without anything happening in the user interface, except for the automagical appearance of the file on the user’s desktop.
Hope it helps,
hubert0
BBEdit.
tell application "BBEdit"
tell document 1
set content to (zap gremlins zap action replace_with_code with use ASCII equivalents and non ASCII characters)
end tell
end tell
From BBEdit’s help documentation:
No need to re-invent the wheel
Almost there.
I need to go to a paragraph (or line), select it and modify it, before pasting it back . Can’t seem to find the right words or order of words.
How can I select a paragraph without replacing it with what is in myText.
Again, I’m quoting from the BBEdit User Manual (14.1.1), page 330:
So don’t go to a line, don’t select, don’t copy, don’t paste - use the application’s object model and scripting dictionary.
Here’s one way of modifying a paragraph in TextEdit:
tell application "TextEdit"
set startingPhrase to "Something at the beginning. "
set finalPhrase to " Something at the end." & return
tell document 1
set oldParagraph to paragraph 4
set nuParagraph to startingPhrase & text 1 thru -2 of oldParagraph & finalPhrase
set paragraph 4 to nuParagraph
end tell
end tell
This concatenates a starting phrase, then “text 1 thru -2 of oldParagraph” - the paragraph without its last character, a return - and then a final phrase and a concluding return.
startingPhrase, finalPhrase, oldParagraph and nuParagraph are text variables.
But without knowing exactly how you want to modify the paragraph, it’s hard to give more concrete advice.
Thanks and Apologies. Found my error.
TextEdit doesn’t like being called a “process” when doing this. I know I also tried it this way without using “System Events” and using TextEdit as an application. But kept getting the error “Can’t get paragraph of TextEdit”. But I think I had “set frontmost to true” instead of “tell document 1”.
Some things seem to work and others don’t in different situations.
I wanted you to leave me something to do in the way of programming Applescript.
The example you left me is the fasted of the 3 I have written so far. But I still feel it should be faster yet.
This is my working script right now. I use it to remove the ascii part of hex dumps by reducing each paragraph to exactly 48 characters, and ignore any empty lines or lines less than 48 characters.
tell application "TextEdit"
tell document 1
set i to 2
repeat
repeat with x from 1 to 33
set oldPara1 to paragraph i
set fir_char to character 1 of oldPara1
if fir_char is "<" or fir_char is return then
set i to i - 1
exit repeat
end if
set paragraph i to text 1 thru 48 of oldPara1 & return
set i to i + 1
end repeat
set i to i + 2
end repeat
end tell
end tell
The biggest thing that baffles me is that the larger the document (more paragraphs) that are in the document, the slower the “paragraph” function gets.
For example, if I only have 16 paragraphs, this applescript if very fast. But if I have 10,000 paragraphs, but I still only want to work on the first 16 paragraphs, this is extremely slow.
What is the “paragraph” function doing that it cares how large the rest of the document is that it makes editing the first few lines extremely slow? I can manually copy and paste faster than the speed it is slowed down to.
Paragraphs aren’t stored as such by applications. The default AppleScript implementation of this builds a list of the paragraphs, and then returns the one you want. Building the list of 10,000 takes longer than a list of a dozen or so.
Applications can write faster code for specific cases like this, but most don’t. The default code has to be generic enough to deal with all sorts of collections, and trades efficiency for the ability to be used generally.
It’s generally quicker to get the text in one go, and manipulate it all in AppleScript itself.
But wouldn’t the list only need to be built once, at the beginning before the repeat loop is entered? And not every time through the repeat loop? I can see the pause being at the beginning, when “tell document 1” is called. But after that, with all paragraphs put into a list, it should be instantaneous to find any paragraph.
I think I thought of the answer after I wrote this. I am setting a new, shortened paragraph back to the document each time through the loop which probably forces the paragraph list to be re-built each time.
Another option maybe!
Would it then be possible to work on the document as a whole, using the “return” mark as a marker and skip the paragraph function? I have to count the characters in each paragraph anyways, so how about a script that keeps track when it encounters one “return” mark to the next, and calculate the count difference between the two? Although I don’t know how to replace the text in that instance.
And one last option:
One of my other scripts used “SystemEvents” and the process “TextEdit”. The script is quite fast in this case, but I was limited to a portion of the document at a time. Is there a way to shorten the clipboard within the process? This is what I have and what is needed for it to work.
tell application "TextEdit"
set nlines to count paragraphs of document 1
end tell
tell application "System Events" to tell process "TextEdit"
set frontmost to true
repeat with i from 1 to nlines
set the clipboard to i as text
keystroke "l" using command down
keystroke "v" using command down
keystroke return -- this highlights and selects a paragraph
delay 0.15
keystroke "c" using command down
-- I need to shorten the clipboard to 48 bytes here or keep the same length if any shorter?
keystroke "v" using command down
end repeat
end tell
Hello, @lamRob,
Your script in the post #11 contains a lot of superfluous, and in the root is incorrect. Because you do not consider that Textedit paragraphs contain rich text.
Therefore, to circumcise the paragraphs will have to simply destroy their redundant characters:
tell application "TextEdit"
activate
tell document 1 to tell its text
set aCount to count its paragraphs
repeat with i from 1 to aCount -- or, indicate 16 (as you want)
if (count characters of its paragraph i) > 49 then ¬
delete characters 49 thru -2 of its paragraph i
end repeat
end tell
end tell
NOTE: do not delete character -1 because it is paragraph delimiter character in the Textedit (return)
Did a few tests, striving for speed. Some things of note:
tell document 1 “to tell its text” – the quoted part saves 5 seconds if document is a .rtf file
– and not needed if document is already a text document, which is what I am working with
deleting characters is twice as slow as getting the characters in a forward collection. This:
if (count characters of its paragraph i) > 49 then ¬
delete characters 49 thru -2 of its paragraph i
is twice as slow as this
set Para to paragraph i
set nCount to count of Para
if nCount > 49 then set paragraph i to text 1 thru 48 of Para
And one final optimization working with the document as a whole. Using the “character” command instead of the “paragraph” command.
tell application "TextEdit"
activate
tell document 1
set done to return & return & "<Delete all after here>" & return & return
set cdone to count characters of done
set cnt to count characters
set x to 1 -- characters
set y to 1 -- start of each paragraph
repeat
set cntr to 1
repeat
set c to character x
set x to x + 1
set character y to c
set y to y + 1
set cntr to cntr + 1
if c is return then set cntr to 0
if cntr is 50 then exit repeat
end repeat
repeat
set c to character x
if c is return then exit repeat
set x to x + 1
end repeat
if character (x + 2) is "[" then exit repeat
end repeat
repeat with i from 1 to cdone
set c to character i of done
set character y to c
set y to y + 1
end repeat
beep
end tell
end tell
This last code is about 5-7 times faster than previous methods. No slow down with 10,000 lines.
One major caveat though. This method seems to tie up the resources in TextEdit which does a lot of disk accessing when trying to save the document. Have to wait 3-5 minutes just to save the modified document. And even then have to reboot the computer to get full operation back to full operation. This part is a little frustrating, but still way faster than other methods.
Is there any particular reason for you to use TextEdit?
You do not need to if you simply want to modify text files with AppleScript.
You do not even have to have the files open on screen.
You can use AppleScript’s built-in text processing commands and the job will be far far faster than anything you can achieve with TextEdit.
As I understand it, you want to take a plain text (.txt) file of 10,000 paragraphs and modify it so that every paragraph longer than 48 characters is cut to its first 48 characters. I don’t understand what you want to do with the shorter paragraphs - leave them in the final version untouched, or remove then entirely? Either is possible.
To illustrate one way of modifying the text, I first built a text file of 10,000 lines of random characters and spaces, with paragraph lengths ranging from 35 to 55 characters.
I then ran the following script, which reads my text file, asks for a new file to place the modified text, creates an empty text variable, then loops through each paragraph of the original text, chops it to 48 characters if it’s any longer, then adds the paragraph (chopped or not) to the new text variable). When it’s finished looping, it writes the 10,000-paragraph new text variable into the specified file. The original text file is untouched.
It doesn’t require TextEdit, or System Events. It’s bare AppleScript.
set longText to read (choose file with prompt "Choose a file whose text is to be cut:")
set shortFile to (choose file name with prompt "Create a new file for the chopped-down text:")
set parCount to count paragraphs in longText
set shortText to ""
repeat with x from 1 to parCount
set nextPar to paragraph x of longText
set charCount to count characters in nextPar
if charCount > 48 then --paragraph returns aren't counted
set shortText to shortText & text 1 thru 48 of nextPar & return
-- remove the following two lines if the shorter paragraphs are to be dropped altogether
else
set shortText to shortText & nextPar & return
end if
end repeat
end
set shortFileWrite to (open for access shortFile with write permission)
try
write shortText to shortFileWrite
on error
close access shortFileWrite
end try
close access shortFileWrite
display dialog "Finished chopping!" buttons {"OK"} default button 1 giving up after 30
I don’t know if it does exactly what you want, and I’m sure there are faster ways of doing it. But it takes less than ten seconds on my machine and doesn’t require any sort of rebooting.
Is there any particular reason for you to use TextEdit?
Nope. I should have clued in to using this method myself with using Applescript’s variables. But it mostly shows my inexperience with Applescript. I am mostly unsure of Applescripts limits with variables and execution.
I assumed Applescript was mostly used just to make operations automatic on open applications.
Thanks for the hint. It opens up a lot more doors for me and helps to understand some of the more complicated posts on this forum.
As I understand it, you want to take a plain text (.txt) file of 10,000 paragraphs and modify it so that every paragraph longer than 48 characters is cut to its first 48 characters. I don’t understand what you want to do with the shorter paragraphs - leave them in the final version untouched, or remove then entirely? Either is possible.
The following is an ASObjC suggestion. It creates a new file with the text “(trimmed)” appended to the file name. The RegEx code was written by Nigel.
use framework "Foundation"
use scripting additions
on main()
set sourceFile to POSIX path of (choose file)
set firstCharacter to 1 -- first character of retained substring
set numberOfCharacters to 48 -- length of retained substring
set trimThreshold to 48 -- minimum required length to trim a paragraph
set theString to current application's NSString's stringWithContentsOfFile:sourceFile encoding:(current application's NSUTF8StringEncoding) |error|:(missing value)
set theDelimiters to (current application's NSCharacterSet's newlineCharacterSet())
set theArray to (theString's componentsSeparatedByCharactersInSet:theDelimiters)'s mutableCopy()
set substringSearchPattern to "(?s)(?<=\\A.{" & firstCharacter - 1 & "}).{" & numberOfCharacters & "}"
repeat with i from 1 to (theArray's |count|())
set aParagraph to (theArray's objectAtIndex:(i - 1))
if (count (aParagraph as text)) > trimThreshold then
set substringRange to (aParagraph's rangeOfString:(substringSearchPattern) options:(current application's NSRegularExpressionSearch))
set substringText to (aParagraph's substringWithRange:(substringRange))
(theArray's replaceObjectAtIndex:(i - 1) withObject:substringText)
end if
end repeat
set theString to theArray's componentsJoinedByString:linefeed
set targetFile to getTargetFile(sourceFile, " (trimmed)")
(current application's NSString's stringWithString:theString)'s writeToFile:targetFile atomically:true encoding:(current application's NSUTF8StringEncoding) |error|:(missing value)
end main
on getTargetFile(theFile, theText)
set theFile to current application's NSString's stringWithString:theFile
set fileExtension to theFile's pathExtension()
set fileNoExtension to theFile's stringByDeletingPathExtension()
return (fileNoExtension's stringByAppendingString:theText)'s stringByAppendingPathExtension:fileExtension
end getTargetFile
main()
It should be noted that this script utilizes UTF-8 character encoding, which could be an issue depending on the contents of the text.
There could be issues with what constitutes 48 characters, given that NSString ranges are effectively based in 16-bit unichar units. It’s probably not a problem in this case, but if there is a chance of multi-unit characters, it gets a bit complex/impractical for ASObjC.
Ahem Peavine!
That is way beyond my comprehension. I will take the 10 sec one over the 2 sec one any day.
But for what it’s worth, I am already done. My computer did it in roughly 15-20 secs, but even at that I was able to do 125 files in under 2 hours.
Thanks for everyone’s help.