Let me preface this by saying that I know that I can easily do the following using a calculated Apple Script from Filemaker. I'd really love to know how to accomplish this inside an Apple Script. I'm trying to set variables into a macro program called Keyboard Maestro that I will refer to as KM.
My script first steps through found records in Filemaker and copies data from each found record. I can't figure out how to set a KM Variable from a loop in Apple Script because, as far as I know, you can't dynamically set the names of Apple Script variables.
I can create the names (that i would like to use) of the variable by creating a list with:
set variableListFunderName to {}
set i to 1
repeat until i = winCount + 1
copy "Business_ExistingAdvance" & i & "FunderName" to the end of variableListFunderName
set i to i + 1
end repeat
set variableListFundingCurrentBalance to {}
set i to 1
repeat until i = winCount + 1
copy "Business_ExistingAdvance" & i & "FundingCurrentBalance" to the end of variableListFundingCurrentBalance
set i to i + 1
end repeat
set variableListFundingAmount to {}
set i to 1
repeat until i = winCount + 1
copy "Business_ExistingAdvance" & i & "FundingAmount" to the end of variableListFundingAmount
set i to i + 1
end repeat
--
But when I set the contents of my fields to the list items that I created, the variables don't show up in KM:
--
set i to 1
repeat until i = winCount + 1
tell record i
set item i of variableListFunderName to cell "Funders_ExistingAdvances::FunderCompanyName"
set item i of variableListFundingCurrentBalance to cell "FundingCurrentBalance"
set item i of variableListFundingAmount to cell "FundingAmount"
end tell
ignoring application responses
tell application "Keyboard Maestro Engine"
setvariable item i of variableListFunderName & "_AS" to item i of variableListFunderName
setvariable item i of variableListFundingCurrentBalance & "_AS" to item i of variableListFundingCurrentBalance
setvariable item i of variableListFundingAmount & "_AS" to (item i of variableListFundingAmount)
end tell
end ignoring
set i to i + 1
end repeat
How can I setup these KM variables?
You cannot create dynamic variables with applescript.
What you currently do is to generate strings and add them to a list. Then you REPLACE these strings with other values so the strings are lost.
But you could achieve this with the help of applescript objective-c:
use framework foundation
set variableListFunderName to {}
set i to 1
repeat until i = winCount + 1
copy "Business_ExistingAdvance" & i & "FunderName" to the end of variableListFunderName
set i to i + 1
end repeat
set funderNameDict to current application's NSMutableDictionary's alloc()'s init()
repeat with var in variableListFunderName
funderNameDict's setObject:"yourValue" forKey:var
end repeat
Then you can access the dynamic values with
set myValue to funderNameDict's objectForKey:"yourDynamicVarName"
to loop through the dictionary use
repeat with theKey in funderNameDict's allKeys()
set myValue to funderNameDict's objectForKey:theKey
end repeat
Related
I have tried so many methods from the removeduplicates, selections and scripting dictionaries and I cannot get this to work. I do understand there are multiple ways to do this but if any of you can help, that would be great.
I have one list of values that I am pulling through from another sheet (up to approx 80k rows) into cell B13 downwards. I am then trying to remove the duplicate values and cells so I am left with unique values which I can then use to perform lookups on other sheets.
Sub Address_Sage()
Dim dataBook As Workbook
Dim dict As Object
Dim Sage_Data As Worksheet, Address As Worksheet
Dim dataSource As Range, dataDest As Range
Dim sourceDataRowCount As Integer, index As Integer
Dim rowCount As Long
Dim strVal As String
Set dataBook = Application.ThisWorkbook
Set sheetSource = dataBook.Sheets("Sage_Data")
Set sheetDest = dataBook.Sheets("Address")
Set dict = CreateObject("Scripting.Dictionary")
Set dataSource = sheetSource.Range("A3", _
sheetSource.Range("A90000").End(xlUp))
sourceDataRowCount = dataSource.Rows.Count
Set dataDest = sheetDest.Range("B13", "B" & _
sourceDataRowCount)
For index = 1 To sourceDataRowCount
dataDest(index, 1).Value = dataSource(index, 1).Value
Next index
Sheets("Address").Select
rowCount = ActiveSheet.Range("B13").CurrentRegion.Rows.Count
Do While rowCount > 0
strVal = Address.Cells(rowCount, 1).Value2
If dict.exists(strVal) Then
ActiveSheet.Rows(rowCount).EntireRow.Delete
Else
dict.Add strVal, 0
End If
rowCount = rowCount - 1
Loop
'Set dict = Nothing
End Sub
It always gets stuck on strVal line. I have tried changing value2 to value1 as I only have column but no luck.
thank you
Not super experienced in VBA so I can't speak to exactly what you're doing and what your code is saying but I thought I'd share this with you. Last week I had to create a macrobook that returned the unique entries of electrical defects that different crews observed while on the job. I made a dictionary that read all of the entries in the spreadsheet and then later printed all of the unique entries. I'll post the code and try to walk you through it.
If .Range("A" & i) <> "" Then
If dict.Exists(data) Then
dict(data) = dict(data) + 1
Else
dict.Add Key:=Data, Item:="1"
End If
End If
So the code basically says if column A (i is simply an incrementer) is not empty, then we're going to read the entries of column A. Data is simply a variable and you would set it equal to the range of values you'd like read in the dictionary. Obviously dictionary keys are unique and cannot repeat, so the code asks if the key already exists in the dictionary. If so, we will add one to it's count or value. And if not we will add that key to the dictionary. At the end of your loop, your dictionary will have stored all unique entries and the number of times they appeared.
Now we can reference them or print them.
For r = 0 To dict.Count
Sheets("Results").Range("B" & iResults) = dict.Keys(r)
Sheets("Results").Range("C" & iResults) = dict(dict.Keys(r))
Next
This second piece of code is a loop from 0 to the number of entries in your dictionary. It starts at zero because the dictionary is stored like an array and VBA arrays are base zero. The first statement will print the unique keys for every r until there are no more entries in the dictionary. The second statement will print the value or items associated with them. It will be an integer value equal to the number of times that unique entry showed up in your data.
You can use this same method for other purposes as well, not just printing the data but referencing it and using it somewhere else. But I am sure you will find that the For-loop with dict.Keys(r) is the easiest way to run through your dictionary entries. Took me a few days to figure it out and it revolutionized my program. Hope this helps you out.
So I am running a Do loop that cycles through a list. I used the 'index' function to calculate the value in the cell. I have a cell that is set up as the 'index' and another cell set up as the value, which is where the index function resides.
The script will start with 'index' = 1 the run. Once it's done, the script adds 1 to the 'index' and the script runs again. This continues until the cell is 0.
Most of the time this runs without any issues, but every once in a while the loop doesn't add correctly. So what happens is the loop occurs but without adding 1 to the index therefore staying on the same value over and over again. This will happen maybe 2 or 3 iterations before finally adding 1 to the index.
Any idea why this is happening? It's really frustrating because this is used to email a large audience with reports that are unique to user. So when it glitches like this, some users are receiving incorrect reports or multiple reports.
Thank you!
Do
y = Worksheets("index").Range("district_num")
xlsheet.Range("A2:Z150000").ClearContents
Set db = OpenDatabase(DbLoc)
SQL = "SELECT DISTINCT district_num, district_name, district_manager_name, last_name2, first_name2, " & _
"district_mgr_job_title, district_mgr_ee_id, DM_email_email_tbl " & _
"FROM Contacts " & _
"WHERE district_num = " & y
'Execute query and populate the recordset'
Set rs = db.OpenRecordset(SQL, dbOpenSnapshot)
'Paste Access data in Excel worksheet'
xlsheet.Range("A2").CopyFromRecordset rs
Application.Cursor = xlDefault
'Skips over empty zones'
If Range("A2") <> vbNullString Then
Call Sheet5.DM_auto_email
Else
Sheets("ZD_contact_list").Select 'Important to go back to the contact list so script can continue to run'
End If
Worksheets("Index").Range("district_num_index") = Worksheets("Index").Range("district_num_index") + 1
Loop Until y = 0
I'm trying to replace every 10th word in a Word document with underscores equal to the length of the word. This is the code that I've tried so far but it doesn't seem close to working. I'm new to VBA. I feel like I'm able to move between words using the FOR EACH loop but I'm having trouble working the selection object
Sub Macro1()
'
' Macro1 Macro
'
'
i = 0
For Each aword In ActiveDocument.Words
' Selection = aword
i = i + 1
aword.Select
If (i Mod 10) = 0 Then
blanks = ""
For Counter = 0 To Len(aword)
blanks = blanks + "_"
Next Counter
Word.Selection.TypeText (blanks)
aword.Cut
End If
Next aword
End Sub
Also, is VBA the easiest language available for doing something like this in a word processing document? Is there a simpler one? I'm trying to help a student who last coded with Wang VS Glossary Decision Processing language https://en.wikipedia.org/wiki/Wang_Laboratories#Wang_OIS
If you are just starting out, VBA is probably the easiest whenever you are working directly with Microsoft Office documents. The main reason is that the functionality is already embedded in the program so you can easily test your scripts from within the application.
Your code almost works once you take out aWord.Cut. Just be aware that certain things are treated as part of the Word collection that you might not expect. For instance, a comma with a space after it is treated as a "word". Same with a period. In the code below I tested for those two conditions but you may need more test depending on what your data looks like.
Lastly I needed to change your loop a bit because once you modify the collection, the iterator in the for each loop resets to what you modified. So in your example, every ninth word after the first would get changed.
i = 1
For Each aword In ActiveDocument.Words
If (aword <> ". " And aword <> ", ") Then
i = i + 1
aword.Select
If (i Mod 11) = 0 Then
blanks = ""
For Counter = 1 To Len(aword) - 1
blanks = blanks + "_"
Next Counter
blanks = blanks + " "
Word.Selection.TypeText (blanks)
End If
End If
Next aword
So I have two columns 17&18 where I have multiple rows such as:
17 | 18<br>
ttt | xxx<br>
tty | xxy<br>
eer | eet<br>
fff | fft<br>
etc...
What I want to do is start at Row 2 Column 17, grab ttt and then see if that occurs again in either column 17 or 18. If it doesn't I need to display a message to the user and if it does, say Row 20 Column 18 I need to ignore it and mark that I've already found this value and don't want to come across it again when I get down there.
I hope this makes sense ...
I think the right thing to do is to use a Do loop and look at something like:
Dim X As Range
Do While Cells(X, 17) <> ""
Do While Cells(X,18) <> ""
Cells.Find(What:=X.Value, After:=activeCell).Active
Loop
Loop
Has anyone tried to do this before?
I wouldn't use the range .Find method for this. Use simply the Application.Match function or the WorksheetFunction.CountIf function. In order to ignore it on second/subsequent passes, you will need to store the list of values to ignore in memory, I would recommend using a dictionary object for this.
Something like this perhaps (untested):
Sub foo()
Dim column1 as Range
Dim rngToCheck as Range
Dim r as Range
Dim dict as Object
'use a dictionary object to keep track of the items that appear more than once
Set dict = CreateObject("Scripting.Dictionary")
Set column1 = Range("A1:A100") 'Modify as needed -- only the first column
Set rngToCheck = Range("A1:B100") 'Modify as needed -- both columns
'Check each value in column1 against the entire range
For each r in column1
'ignoring anything that already has been added to the dictionary
If not dict.Exists(r.Value) Then
If WorksheetFunction.CountIf(rngToCheck, r.Value) > 1 then
'if it appears more than once then add it to the dictionary so to ignore
' it the next time the macro encounters this value:
dict(r.Value) = dict(r.Value)
Else
'if this value only appears once, then it doesn't appear anywhere else, _
' so msgbox to the user. Modify msgbox as needed:
MsgBox r
End If
End If
Next
End Sub
For my VBS script, for each loop, I want it to add the number of which loop it's on. Like if it's a site and has an ID, then if it's on loop 1 adds 1 to the ID. I already declared "site" for my script.
What do I do? Do you need to see some of the script?
Not sure what kind of collection you're working with, but you could do something simple like this
Set objFilesystem = CreateObject("Scripting.FileSystemObject")
Set objInputFolder = objFileSystem.GetFolder("c:\temp")
i = 1
For Each objInputFile In objInputFolder.Files
WScript.Echo SITE + i
i = i + 1
Next