I'm working on an AppleScript that is calling a Python script with the name of a file as an argument, something like :
set descriptionFiles to (every file of current_folder whose name extension is "txt")
repeat with textFile in descriptionFiles
-- run a Python script that clears the xml tags and reformat the text of the file
do shell script "python3 '/Users/MBP/Documents/Python/cleanDescription.py' '" & textFile & "'"
end repeat
Now the AppleScript does fine as long as I'm not encountering a file with a single quote in it's name at which point it stops and throws an error.
To correct that, I've been trying to escape the single quote in the files name before passing it to the Python script but that's where I'm stuck. I'm using this routine :
on searchReplace(thisText, searchTerm, replacement)
set AppleScript's text item delimiters to searchTerm
set thisText to thisText's text items
set AppleScript's text item delimiters to replacement
set thisText to "" & thisText
set AppleScript's text item delimiters to ""
return thisText
end searchReplace
with a call like this :
tell application "Finder"
set search_T to "'"
set rep to "\\'"
set selected to selection as alias
set textName to selected as text
set res to searchReplace(textName, search_T, rep)
end tell
Using the code above on a single file throws an error on the searchReplace(textName, search_T, rep) part, with a number of -1708
Any ideas ?
The most reliable way to escape special characters in AppleScript is quoted form of. It handles all forms of quotation smoothly. Never do it yourself. It's also a good practice to quote paths always in do shell script lines even if they don't contain spaces.
Another issue is that textFile is supposed to be a POSIX path rather than a Finder specifier. And get the path to the python script once
set pythonScriptPath to POSIX path of (path to documents folder) & "Python/cleanDescription.py"
set descriptionFiles to (every file of current_folder whose name extension is "txt")
repeat with textFile in descriptionFiles
-- run a Python script that clears the xml tags and reformat the text of the file
do shell script "python3" & space & quoted form of pythonScriptPath & space & quoted form of POSIX path of (textFile as text)
end repeat
Related
I have a text file that is automatically generated from a machine. The machine writes the txt file in "chunks" (sorry I don't know the exact terminology). I need to pull data from this txt file, but I need the txt file to be finished before pulling data from it. I found a solution to verify that the machine has finished writing to the file... It is not as elegant as i had hoped, but seems to do the trick. Excel VBA opens a command prompt, the command prompt uses a Find command to find the string "End of Report"... This is basically one of the last lines of the txt file and pretty safe to assume the txt file is finished after this is found. This code runs in a loop 1000 times, every 10 seconds, until it finds this string or reaches 1000 tries...
The issue is that "result" returns some other characters besides just "End of Report" this is further complicated by the fact that I am attempting to run this on some csv files too... and "result" returns some additional characters also, but different from the ones returned from the txt files. For example, if I check the length of "result"... The length comes back as 43 on one file and 48 on another file... I think it is counting the file path + "End of Report" + a few more characters?
Anyways, I don't really need the "result"... I really only need a "true" / "false" if "Find" found "End of Report" or not... How can I accomplish this? Is there a different better way to do this? I am not familiar with command prompt programming.
Note: It is important that I search these files without opening them.
Sub test()
Dim SearchStr As String
Dim cmdLine As Object
Dim result As String
Dim FilePath As String
FilePath = "D:\test2.txt"
SearchStr = """End of Report"""
Set cmdLine = CreateObject("WScript.Shell")
result = cmdLine.Exec("%comspec% /C Find " & SearchStr & " " & Chr(34) & FilePath & Chr(34)).STDOut.ReadAll
Debug.Print (result)
End Sub
I am not really an expert in command line, but what I would do is export the result of the FIND command to a file, like here
Then I would check in your VBA code how many rows are in the file (either clean the file before, or check the number of rows before the export is done).
If the number of rows meets the criteria (probably 2 or more rows instead of 1), then you can set the flag to True.
I am trying to build an AppleScript that reads each line of a “.txt” file (with a linefeed) and stores the contents of each line into AppleScript variables.
Here is what I mean:
Let’s say there was a “Test.txt” file with the contents:
Apples
Oranges
Pears
As you can see, the “Test.txt” file’s contents have a String on each line, a linefeed introducing the new String, and so on.
I would really like to know how an AppleScript could be made so that each line’s Strings are copied into individual AppleScript variables.
(This way, “Apples” in the first line, would be stored in variableA, “Oranges” in the next would be stored in variableB, “Pears” … variableC, etc.)
Please let me know, from your experience, how best to accomplish this. I know it’s slightly more involved, here is where I am:
(*
This portion of the AppleScript accesses the contents of the ".txt" file named "Test," though takes all of the content and places it into a single variable.
*)
set newFile to ("Macintosh HD:Users:Username:Desktop:Test.txt")
set theFileContents to (read file newFile)
{ AppleScript code to read each line to individual variables }
I know there must be others trying to accomplish this.
This example is for a situation where you know the anticipated paragraphs you'll be looking for to assign to each of a known set of variables.
set newFile to ("Macintosh HD:Users:Username:Desktop:Test.txt")
set theFileContents to paragraphs of (read file newFile)
set recipientEmail to paragraph 1 of theFileContents as text
set senderEmail to paragraph 2 of theFileContents as text
set theSubject to paragraph 3 of theFileContents as text
set theBody to (paragraphs 4 thru -1 of theFileContents) as text
Another option would be to dynamically search for a string in the paragraph, and if it matches, then assign it to that variable. Something like:
set newFile to ("Macintosh HD:Users:jweaks:Desktop:horses.txt")
set theFileContents to paragraphs of (read file newFile)
set recipientEmail to ""
set senderEmail to ""
set theSubject to ""
set theBody to ""
repeat with p in theFileContents
if p contains "To:" then
set recipientEmail to p
else if p contains "From:" then
set senderEmail to p
else if p contains "Subject:" then
set theSubject to p
else
set theBody to theBody & p & return
end if
end repeat
Thank you so much for all of your effort to answer this question, jweaks. As I am still catching on to AppleScript best practices, I was thinking more about your recommendation of bringing the contents of the “.txt” file into a list, assigning the items to AppleScript variables (if needed), and began brainstorming how to accomplish it. I agree that it seems like the simplest and most efficient approach:
Reads the “.txt” file’s into a list of items: Apples, Oranges, and Pears
set paragraph_list to read file "Macintosh HD:Users:tombettinger:Desktop:Test.txt" using delimiter linefeed
Apples
set variableA to item 1 of paragraph_list
Oranges
set variableB to item 2 of paragraph_list
Pears
set variableC to item 3 of paragraph_list
Displays the contents of each variable (optional comment)
display dialog variableA & " " & variableB & " " & variableC
End of AppleScript
As long as the contents of the ".txt" file are stacked in a table, this approach will support the accessibility of information I was searching for. Thanks again!
Spell Check is a default application in Linux. With the help of that application, can we check the spelling of a text field while users enter data?
Some (or many?) Linux distributions contain a command line utility that is called spell. If you run this with words as parameters, you need to press return a second time, but if you use a file as a paramater, you don't need to press return again. This means that a solution could be:
write the text of a field to a file
run the command line utility from LiveCode's shell function with the file as parameter
parse the result returned by the shell function
Before you try this, open your terminal on Linux and type spell. Press enter to see if the command is recognised. If yes, then the script below should work.
This script writes the text of a field to a file, does a spell check on the file and returns the incorrect words to LiveCode. I haven't tested the script and you may have to tweak it a little.
function spellCheck theText
// works on Linux only
if the platform is "Linux" then
// remove everything that isn't a word
put replaceText(theText,"[^\w]","") into myWords
// write clean data to a temporary file
put the tempName into myTempFile
put myWords into url ("file:" & myTempFile)
// call spell with shell
put "spell" && myTempFile into myShell
// only return the incorrect words
put line 2 to -1 of shell(myShell) into myCorrections
// return the incorrect words to calling handler
return myCorrections
else
// this isn't Linux
return "error"
end if
end spellCheck
//theField is the short name of a field
on checkField theField
// call above function
put spellCheck(the text of fld theField) into myWords
// myWords should now contain the incorrect words
if myWords is not "error" then
lock screen
// parse incorrect words and mark them in the field
repeat with x = 1 to number of words of field theField
if myWord is among the lines of myWords then
// an incorrect word has been found and is marked red
set the textColor of word x of fld theField to red
end if
end repeat
unlock screen
end if
end checkField
Usage: checkField shortNameOfTheField
Request assistance with truncating/trimming a string in an automator action used to create text-to-speech audio files from a text selection ranging from 30 or so characters to 800+, which is too long for a file name.
In short, I am trying to truncate a string to 30 characters and pass that to the "Text to Audio File" action as the file name.
Basic workflow is:
Select text
Initiate following Automator Action via Services Menu
"Set Value of Variable" to input (e.g. selected text) and define as TextToSpeech
"Set Value of Variable" to input (e.g. selected text) and define as FileName
"Get Value of Variable" FileName
"Run AppleScript"
on run {input, parameters}
set theResult to input as string
set finalResult to input as string
set txtLength to (length of theResult)
if txtLength > 30 then
set finalResult to (characters 1 thru 30 of theResult) as string
end if
return finalResult
end run
"Set Value of Variable" input (e.g. selected text) and define as FileName
"Get Value of Variable" TextToSpeech
"Text to Audio File" with Save As: set to "FileName"
"Encode to MPEG Audio"
Any assistance/suggestions is greatly appreciated!
Regards,
Zephyr
In general you pass from the applescript to the next action whatever it needs using the "return" command at the end of the code. In your case though the automator action "Text to Audio File" doesn't accept a fileName variable so if you want that much control you need another method. Luckily that automator action can be replaced easily in the applescript code with a simple "say" command.
So create your automator service and receive the selected text. Then add an applescript action and use the following as the code. Then add an "Encode to MPEG audio" action.
For the applescript code just modify the voiceName and saveFolder variables with values of your choosing. The saveFolder path must end with a colon (:). Note that I use 26 instead of 30 because we add ".aif" to the end of the filename... to get a total of 30 characters.
on run {input, parameters}
set voiceName to "Jill"
set saveFolder to path to desktop as text
set selectedText to item 1 of input
if (length of selectedText) > 26 then
set fileName to text 1 thru 26 of selectedText
else
set fileName to selectedText
end if
set fileName to fileName & ".aif"
set filePath to saveFolder & fileName
say selectedText using voiceName saving to file filePath
return {POSIX path of filePath}
end run
If you need to determine your saveFolder use this to get the path. Run this code and copy/paste the result into the saveFolder variable above.
(choose folder) as text
Here's what worked:
Select text
Initiate following Automator Action via Services Menu
"Set Value of Variable" to input (e.g. selected text) and define as TextToSpeech
"Run AppleScript"
on run {input, parameters}
set theResult to input as string
set finalResult to input as string
set txtLength to (length of theResult)
if txtLength > 50 then
set finalResult to characters 1 thru 50 of theResult as string
end if
return finalResult as string
end run
"Set Value of Variable" input (e.g. selected text) and define as FileName
"Get Value of Variable" TextToSpeech and ignore this action's input
"Text to Audio File" with Save As: set to "FileName" and the save as location set.
"Encode to MPEG Audio"
Result: an audio file of the selected text spoken by the desired voice with a file name set to the first 50 characters of the selected text.
( I increased to characters to lessen the number of duplicate file names I was getting as part of my workflow.)
#regulus6633 : your answer is more compact, and elegant, but I need to learn more about how applescript gets it's inputs and returns it's results. Thanks again.
I am currently using this Applescript I found that searches for a file name and returns the file path in a text doc. This works fine for finding 1 or 2 files, but I would like to find 500 files that are spread over hundreds of folders. My ideal script would use data from an excel spreadsheet or csv, perform a search, find the file and make a copy of it in a designated folder on my desktop. Any help is appreciated.
Here is the script I found:
tell application "System Events"
activate
set thePattern to text returned of (display dialog "Search for" default answer "")
end tell
if thePattern = "" then return
try
set foundFiles to do shell script "mdfind -name " & quoted form of thePattern & " | /usr/bin/egrep -i " & quoted form of thePattern & "[^/]*/?$ | /usr/bin/grep -vi " & quoted form of thePattern & ".*" & quoted form of thePattern
on error
set foundFiles to "Nothing Returned"
end try
if foundFiles = "" then set foundFiles to "Nothing Returned"
tell application "TextEdit"
activate
delay 0.5
try
set theDoc to document 1
get text of theDoc
if result is not "" then
make new document
set theDoc to result
end if
on error
make new document
set theDoc to result
end try
set text of theDoc to foundFiles
end tell
You need to read the data from the text file, then turn it into a return or linefeed delimited list and do a repeat over the items of this list. Then turn each item (which is actually a line) into e.g. a tab delimited list and again do a (nested) repeat loop over the items of this list. If you know that e.g. item 3 is the file path, you can set a variable to item 3 of the line as text and use this variable in your shell script.
I think you need to show that you understand the concept of repeat loops by posting your own attempt of implementing this. If you do, I'll be happy to come back and help you with the next step.
Kind regards,
Mark