Trying to learn how to use AppleScript records and lists to their upmost potential I've been trying to create a report of a BBEdit project but I'm finding very limited documentation. I asked a question yesterday trying to figure out why my find pattern wasn't working but after finding out that the issue was from me lacking returning results:true I was able to get the result record and I verified it was a record after reading Class and running:
class of findFunction
Since it says it's a record I reviewed here and ran length of findFunction and count of findFunction and they both returned 2. I was curious to know what the two items were in the record so I used return findFunction and was told there was:
found: true
found matches: list of X items
Wanting to know where and what files the matches were located in the list, I did some more searching and read Lists and records and ran:
set theMatches to get found matches of findFunction
it returned the list items and checking the new variable with get count of theMatches I am able get the quantity of items in the targeted list inside the record. When I review what's in the list (learned from: How to get a value from a list with a string in AppleScript? and Searching for items in list) I am able to conclude that when using the find in BBEdit every item in the list contains:
end_offset :
match_string :
message :
result_file :
result_kind :
result_line :
start_offset :
Experimenting with an item I set a variable with:
set itemOne to get item 1 of theMatches
and checked to see if it worked with:
display dialog (result_file of itemOne) as text
and a dialog with the full file path was displayed. Trying to utilize DRY I created:
set filesResult to get (result_file of (get item 1 of theMatches)) as text
Wanting to add any of the mentioned above to a file with something like:
set filesResult to get (result_file of (get item 1 of theMatches)) as text
set theMessage to get (message of (get item 1 of theMatches)) as text
set combined to filesResult & ":" & theMessage
I recalled being able to use the clipboard and found Set clipboard to Applescript variable? so I added:
set filesResult to the clipboard
make new text document
paste
but my issue I'm running into is how can I take every item in the list found_matches and add it to the clipboard an item on each line? I thought about using a repeat but I get an error when I try:
repeat with x from 1 to (length of matchesItems)
set filesResult to get (result_file of (get item x of theMatches)) as text
set theMessage to get (message of (get item x of theMatches)) as text
set combined to filesResult & ":" & theMessage
end repeat
With a message of:
The variable matchesItems is not defined.
So how can I get every item from the list into the clipboard with every item on it's own line so I can paste all items from the clipboard into a new file?
To clarify wording
theList = {A,B,C} -- this is a list with 3 variables
theRecord = {A:something, B:somethingElse, C:somethingElseTwo} -- this is a record.
A list can be addressed by its index.
theList's item 1 -- A
A record can be addressed by its keys
A of theRecord -- something
To get all items of a list into a string repeat it by its index (saying every item is of type text)
set finalString to ""
repeat with thisItem in TheList
set finalString to finalString & thisItem & return -- the return creates a new line
end repeat
Then you have finalString to do with whatever you like.
To get every item of a record you have to know it's keys (if it's not a ASOC NSDictionary)
set finalString to ""
set finalString to finalString & A of theRecord & return;
-- repeat last line with every key
Related
I have extracted files from an online database that consist of a roughly 100 titles. Associated with each of these titles is a DOI number, however, the DOI number is different for each title. To program this endeavor, I converted the contents of the website to a list. I then created for loop to iterate through each item of the list. What I want the program to do is iterate through the entire list and find where it says "DOI:" then to take the number which follows this. However, with the for loop I created, all it seems to do is print out the first DOI number, then terminates. How to I make the loop keep going once I have found the first one.
Here is the code:
resulttext = resulttext.split()
print(resulttext)
for item in resulttext:
if item == "DOI:":
DOI=resulttext[resulttext.index("DOI:")+1] #This parses out the DOI, then takes the item which follows it
print(DOI)
How can I only keep words / numbers from list?
I use the follow script and I want to count unique payment methods, but I have unwanted values on my list
I also tried to use "word of item" but this is not working
I try different version of the script but always having an issue
set PaymentMethods to {}
set UniquePaymentMethods to {}
set walletPayement to {}
set mobilePayemnt to {}
tell application "Safari"
set PaymentMethods to do JavaScript "var outPut=[]; var arr=document.getElementsByClassName('sortable Summary');for (var i in arr) {outPut.push(arr[i].innerHTML)};outPut;" in current tab of window 1
end tell
repeat with x from 1 to count of items of PaymentMethods
set n to item x of PaymentMethods
if n is in PaymentMethods and n is not in UniquePaymentMethods and n does not contain "<a href=\"/finance/Support.ok" and n does not contain "Safari" and n does not contain "None" then set end of UniquePaymentMethods to n
end repeat
e.g of the result :
{"
PayPal
", "
MasterCard (999)
", "
MasterCard (888)
", application "Safari"}
It's good that you're generally mindful about supplying a sample of the input, as you've done here with the list that I presume relates to PaymentMethods. But don't forget to also provide the output you want to get back at the end. It took me a while to realise "keep words / numbers from list" was actually referring to items of class text (or string), which was about my fifth interpretation of what was being asked.
Your solution appears to do what you want, but it doesn't really because you've had to use that very case-specific set of conditionals, i.e.:
if n is in PaymentMethods ¬
and n is not in UniquePaymentMethods ¬
and n does not contain ("<a href=\"/finance/Support.ok") ¬
and n does not contain ("Safari") ¬
and n does not contain "None" then ¬
set end of UniquePaymentMethods to n
Without that, the item application "Safari", for instance, would simply be coerced into class text, which would return "Safari" in your resulting list.
So, while your request was to filter a list's data types to contain only text class items, your proposed fix, i.e.:
set n to item x of PaymentMethods as text
doesn't isolate text items; it coerces items of any class into text.
The way to filter a list by class type is to use this syntax:
get every [class] in [list]
where [class] is the AppleScript class you want to keep (discarding any items not of this class), and [list] is the list (or variable that references a list), e.g.:
every text in {1, "Hello", true, missing value, "2", text, number, pi}
--> {"Hello", "2"}
every number in {1, "Hello", true, missing value, "2", text, number, pi}
--> {1, 3.14159265359}
every application in {"PayPal", "MasterCard (999)", "MasterCard (888)", application "Safari"}
--> {application "Safari"}
every text in {"PayPal", "MasterCard (999)", "MasterCard (888)", application "Safari"}
--> {"PayPal", "MasterCard (999)", "MasterCard (888)"}
But, there's a lot you can do to simplify your script by having the initial JavaScript code do the heavy lifting so it returns a cleaner list of items that will be simpler for AppleScript to process, or eliminate any need for additional processing.
Your list items have a lot of whitespace in them. In JS, use trim().
Your AppleScript conditionals reference "innerHTML property without ever wanting to use any actual HTML. You've been consistently interested only in the text that gets printed on your webpage. Therefore, in JS, experiment with innerText applied to the right HTML element and you'll probably be able to isolate the payment methods text straight away.
You appear to want your list to contain unique items. In JS, use sets, which are basically arrays with unique items.
Implementing these three recommendations, together with the above method of filtering by text class, would look something like:
tell application "Safari" to tell document 1 to tell (do JavaScript "
[...new Set( document.getElementsByClassName('sortable Summary') )]
.map( x => x.innerText.trim() );") ¬
to set PaymentMethods to every text
As I don't know what your webpage source looks like, you may need to make slight adjustments to how you want to transform innerText besides trim(), and/or consider whether getElementsByClassName('sortable Summary') is the best way to get access to the parts of the HTML DOM tree you require. querySelectorAll() is a much more powerful method to use, which I have mentioned before.
Found it, need to add the kind for each item
set n to item x of PaymentMethods as text
The problem im getting is if type something in my entry box it first fills index 1 and 2 of the listbox before finally typing into the 3rd index.
def country_get(event):
listbox.delete(3)
listbox.insert(3, country_label.cget('text') + event.widget.get() + '\n')
title_text=StringVar()
entry_country=Entry(master, bg="wheat3", fg="dark slate gray", textvariable=title_text)
entry_country.bind('<KeyRelease>', country_get)
entry_country.grid(row=4, column=1)
I want to be able to type at any index of the listbox whether it be the 3rd or 5th, without having anything at the previous index's.
You can't do what you want. The listbox isn't designed to have empty rows. If you want empty rows, you will need to insert empty strings.
Depending on how many entries I'm using or need, i just insert empty strings like so:
listbox.insert(0, "")
listbox.insert(1, "")
listbox.insert(2, "")
listbox.insert(3, "")
listbox.insert(4, "")
It appears that the listbox is empty when it fact it is just filled with empty strings. There are most likely other ways to get around this, but for what I need my program to do, this is what worked for me.
The list is in the form of:-
0:
https://url
1:
https://url
..... And so on.
How could I loop on this list. So I could fetch the number first without ":" and type it somewhere then fetch the url that comes after that number and type it elsewhere. Then end repeat if the list is over.
Or should I use records instead?
I am still a beginner using AppleScript. I tried many commands I mixed up but the computer keeps running the script nonestop and the activity monitor shows the applescript using 100% of the processor and huge amount of ram.
Appreciate any help.
Thank you
You didn't define what your list really looks like very well so I made an assumption on my answer below. If I was wrong, hopefully my answer will at least point you in the right direction. (or if I've gotten it wrong, but you can choose to reformat it to the way I suggested, that could still help)
on run
set theList to {"0:http://apple.com", "1:http://google.com"} -- my guess at what your list looks like.
repeat with anItem in theList
set anItem to anItem as string
set itemParts to myParseItem(anItem)
set tID to the_integer of itemParts as integer
set tURL to the_url of itemParts as string
end repeat
end run
on myParseItem(theItem)
set AppleScript's text item delimiters to ":"
set delimitedList to every text item of theItem
set newString to (items 2 thru -1 of delimitedList as string)
set AppleScript's text item delimiters to {""}
set theInt to item 1 of delimitedList
set theURL to newString as string
return {the_integer:theInt, the_url:theURL}
end myParseItem
I am trying to just do a basic INSERT operation to a PostgreSQL database through Python via the Psycopg2 module. I have read a great many of the questions already posted regarding this subject as well as the documentation but I seem to have done something uniquely wrong and none of the fixes seem to work for my code.
#API CALL + JSON decoding here
x = 0
for item in ulist:
idValue = list['members'][x]['name']
activeUsers.append(str(idValue))
x += 1
dbShell.executemany("""INSERT INTO slickusers (username) VALUES (%s)""", activeUsers
)
The loop creates a list of strings that looks like this when printed:
['b2ong', 'dune', 'drble', 'drars', 'feman', 'got', 'urbo']
I am just trying to have the code INSERT these strings as 1 row each into the table.
The error specified when running is:
TypeError: not all arguments converted during string formatting
I tried changing the INSERT to:
dbShell.executemany("INSERT INTO slackusers (username) VALUES (%s)", (activeUsers,) )
But that seems like it's merely treating the entire list as a single string as it yields:
psycopg2.DataError: value too long for type character varying(30)
What am I missing?
First in the code you pasted:
x = 0
for item in ulist:
idValue = list['members'][x]['name']
activeUsers.append(str(idValue))
x += 1
Is not the right way to accomplish what you are trying to do.
first list is a reserved word in python and you shouldn't use it as a variable name. I am assuming you meant ulist.
if you really need access to the index of an item in python you can use enumerate:
for x, item in enumerate(ulist):
but, the best way to do what you are trying to do is something like
for item in ulist: # or list['members'] Your example is kinda broken here
activeUsers.append(str(item['name']))
Your first try was:
['b2ong', 'dune', 'drble', 'drars', 'feman', 'got', 'urbo']
Your second attempt was:
(['b2ong', 'dune', 'drble', 'drars', 'feman', 'got', 'urbo'], )
What I think you want is:
[['b2ong'], ['dune'], ['drble'], ['drars'], ['feman'], ['got'], ['urbo']]
You could get this many ways:
dbShell.executemany("INSERT INTO slackusers (username) VALUES (%s)", [ [a] for a in activeUsers] )
or event better:
for item in ulist: # or list['members'] Your example is kinda broken here
activeUsers.append([str(item['name'])])
dbShell.executemany("""INSERT INTO slickusers (username) VALUES (%s)""", activeUsers)