This is a confusing question to ask, so forgive me if the answer is obvious because I have not been able to find one.
I’m trying to figure out how to search some “form” style text for user values ie:
MyFile’s Text-
Part Number: 1234
Part Name: Important Part
I know the format, and I know the Field names (Part Number, Part Name, etc), and need to set variables to the text that follows each field name ie:
partNumber is equal to “1234”
partName is equal to “Important Part”
How would one do that?
This breaks them out into a list of part num, part Name that should be easy to back your data out of.
set myText to "Part Number: 1234
Part Name: Imp Part 1
Part Number: 1235
Part Name: Imp Part 2
Part Number: 1236
Part Name: Imp Part 3"
to getValues(someText)
set vals to {}
set astid to AppleScript's text item delimiters
set AppleScript's text item delimiters to ": "
repeat with P in (paragraphs of someText)
set end of vals to text item 2 of P
end repeat
set AppleScript's text item delimiters to astid
return vals
end getValues
getValues(myText)
--> {"1234", "Imp Part 1", "1235", "Imp Part 2", "1236", "Imp Part 3"}
May not be what your looking for, but here goes… (and I’m sure there is a simplier way to do what I’m accomplishing with this method, but oh well :D)
set recordList to {}
set OTID to AppleScript's text item delimiters
set AppleScript's text item delimiters to ":"
set theFile to choose file
set fileRecords to paragraphs of (read theFile)
if (count of items of fileRecords) mod 2 is 0 then
set loopCount to ((count of items of fileRecords) / 2) as integer
repeat with i from 1 to loopCount
set end of recordList to {partNumber:(text item 2 of item (i * 2 - 1) of fileRecords), partName:(text item 2 of (item (i * 2)) of fileRecords)}
end repeat
else
display dialog "Invalid Data File"
end if
set AppleScript's text item delimiters to OTID
This is probably more than you need, but it has two nice error messages, ignores whitespace before or after the colon, and can also handle colons as part of the field’s value.
set fieldText to "Part Number: 1234
Part Name: Important Part"
set fieldLabels to {{recordLabel:"partNumber", fieldLabel:"Part Number"}, {recordLabel:"partName", fieldLabel:"Part Name"}}
extractFormFieldsIntoRecord(fieldText, fieldLabels)
--> {partNumber:"1234", partName:"Important Part"}
on extractFormFieldsIntoRecord(fieldText, fieldLabels)
set fieldRecord to {}
set text item delimiters to return
set fieldText to return & paragraphs of fieldText as string
repeat with thisItem in fieldLabels
set text item delimiters to return & fieldLabel of thisItem
try
set fieldValue to first paragraph of second text item of fieldText
set colonFound to false
repeat while fieldValue starts with space or not colonFound
if not colonFound and fieldValue starts with ":" then set colonFound to true
set fieldValue to text 2 thru -1 of fieldValue
end repeat
on error
error "Field " & quoted form of (fieldLabel of thisItem & ":") & item ((colonFound as integer) + 1) of {" not found.", " has no value."}
end try
set fieldRecord to fieldRecord & (run script "{" & recordLabel of thisItem & ":\"" & fieldValue & "\"}")
end repeat
set text item delimiters to ""
return fieldRecord
end extractFormFieldsIntoRecord
Thanks for all the responses.
Quick question for Querty,
I want to be able to set each returned value to a unique variable so that the value for field record partNumber becomes a unique variable I can reference later on in the script.
My question is how do I reference the indivudual field label one at a time and assign it’s value to a variable?
Hi vikingshelmut,
To get the value of a particular item of a record, you simply ask using its key, like so:
set theRecord to extractFormFieldsIntoRecord(fieldText, fieldLabels)
--> theRecord: {partNumber:"1234", partName:"Important Part"}
set partNumber to partNumber of theRecord
set partName to partName of theRecord
return {partNumber, partName}
--> {"1234", "Important Part"}
This can also be done in one step, by using a record to identify which parts you want:
set theRecord to {name:"vikingshelmut", kind:"headwear", color:"silver"}
set {name:a, kind:b} to theRecord -- Choose which values we want
return {a, b}
--> {"vikingshelmut", "headwear"}
set theRecord to extractFormFieldsIntoRecord(fieldText, fieldLabels)
--> theRecord: {partNumber:"1234", partName:"Important Part"}
-- Form is {recordValueName : myVariableName}, both names can be identical
set {partNumber:partNumber, partName:partName} to theRecord
return {partNumber, partName}
--> {"1234", "Important Part"}
That works perfectly! Thanks for all the help. I think I understand what was going on now.
I love this place.
Ok, sorry to rehash this post, but I’ve run into a problem.
In the previous example, we were extracting values from a form.
The script searched “fieldText”, found “fieldLables”, and extracted the text “fieldValue” from each occurance:
set theRecord to extractFormFieldsIntoRecord(fieldText, fieldLabels)
--> theRecord: {partNumber:"1234", partName:"Important Part"}
set partNumber to partNumber of theRecord
set partName to partName of theRecord
return {partNumber, partName}
--> {"1234", "Important Part"}
I’ve now run into a problem where in certain circumstances the fieldValue for a particular fieldLabel might be blank. If a field is blank, I get an error message (using field label “Part Number”):
AppleScript Error
Field ‘Part Number’ has no value. (-2700)
I’m not sure where the problem exists in the code, but it could be in this block:
try
set fieldValue to first paragraph of second text item of fieldText
set colonFound to false
repeat while fieldValue starts with space or not colonFound
if not colonFound and fieldValue starts with ":" then set colonFound to true
set fieldValue to text 2 thru -1 of fieldValue
end repeat
on error
error "Field " & quoted form of (fieldLabel of thisItem & ":") & item ((colonFound as integer) + 1) of {" not found.", " has no value."}
end try
Querty, if you are still out there, can you help?
How about something like this:
set theRecord to extractFormFieldsIntoRecord(fieldText, fieldLabels)
--> theRecord: {partNumber:"1234", partName:"Important Part"}
if partNumber of theRecord is missing value then
set partNumber to "N/A" -- or if it will be coerced to a number later "0000"
else
set partNumber to partNumber of theRecord
end if
if partName of theRecord is missing value then
set partName to "N/A"
else
set partName to partName of theRecord
end if
return {partNumber, partName}
--> {"1234", "Important Part"}
Ok, I see where you are going with this Adam, but I tried putting your text outside of the “on extractFormFieldsIntoRecord(fieldText, fieldLabels)” function, and it didn’t work. I figured it must go inside the function, but when I look at the function, I really can’t see where. Can you help me some more? Thanks.
I have included the full function and the call the function below:
set fieldText to "Part Number: 1234
Part Name: Important Part"
set fieldLabels to {{recordLabel:"partNumber", fieldLabel:"Part Number"}, {recordLabel:"partName", fieldLabel:"Part Name"}}
extractFormFieldsIntoRecord(fieldText, fieldLabels)
--> {partNumber:"1234", partName:"Important Part"}
on extractFormFieldsIntoRecord(fieldText, fieldLabels)
set fieldRecord to {}
set text item delimiters to return
set fieldText to return & paragraphs of fieldText as string
repeat with thisItem in fieldLabels
set text item delimiters to return & fieldLabel of thisItem
try
set fieldValue to first paragraph of second text item of fieldText
set colonFound to false
repeat while fieldValue starts with space or not colonFound
if not colonFound and fieldValue starts with ":" then set colonFound to true
set fieldValue to text 2 thru -1 of fieldValue
end repeat
on error
error "Field " & quoted form of (fieldLabel of thisItem & ":") & item ((colonFound as integer) + 1) of {" not found.", " has no value."}
end try
set fieldRecord to fieldRecord & (run script "{" & recordLabel of thisItem & ":\"" & fieldValue & "\"}")
end repeat
set text item delimiters to ""
return fieldRecord
end extractFormFieldsIntoRecord
The handler is doing what it is scripted to do: post the error message:
error "Field " & quoted form of (fieldLabel of thisItem & ":") & item ((colonFound as integer) + 1) of {" not found.", " has no value."}
When you say “I’ve now run into a problem where in certain circumstances the fieldValue for a particular fieldLabel might be blank.”, do you mean that the field value is missing or that the field label is missing? Assuming it’s the value, I see why the solution I proposed won’t work - you go to the “function” (a handler in AppleScript) first and I was correcting the result, which we don’t get (we get the message), so you are correct that you’ll have to deal with it in the handler.
You don’t, however, say what you want to do if a field value is missing. Assuming you want to proceed anyway with something there (like “N/A”, for not available), then a correction like this might work:
set fieldText to "Part Number:
Part Name: Important Part"
set fieldLabels to {{recordLabel:"partNumber", fieldLabel:"Part Number"}, {recordLabel:"partName", fieldLabel:"Part Name"}}
extractFormFieldsIntoRecord(fieldText, fieldLabels)
--> {partNumber:"N/A", partName:"Important Part"}
on extractFormFieldsIntoRecord(fieldText, fieldLabels)
set fieldRecord to {}
set text item delimiters to return
set fieldText to return & paragraphs of fieldText as string
repeat with thisItem in fieldLabels
set text item delimiters to return & fieldLabel of thisItem
set fieldValue to first paragraph of second text item of fieldText
set colonFound to false
repeat while fieldValue starts with space or not colonFound
if not colonFound and fieldValue starts with ":" then set colonFound to true
try
set fieldValue to text 2 thru -1 of fieldValue
on error
set fieldValue to "N/A" -- or whatever you want it to be. It just can't be nothing at all.
end try
end repeat
set fieldRecord to fieldRecord & (run script "{" & recordLabel of thisItem & ":\"" & fieldValue & "\"}")
end repeat
set text item delimiters to ""
return fieldRecord
end extractFormFieldsIntoRecord
Adam,
Thanks, that did it. I was eyeballing that “error” section and figured something should go there, but my scripting newbiness prevented me from seeing the solution.
Thanks again, this is one great site. Hopefully someday i’ll be answering other peoples questions!
Note too, VH, that I changed the range of the try block - it’s not where it was, but now singles out the absence of data. We could have tested the field value as well with an if block, but this works no matter what the screw up is and the if would have been specific.
Also, you’re welcome. 