Searching for form values in plain text

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. :wink: