How can I search delimited data for a matching string?

Working with text is one of the areas where LiveCode shines most. Here I explain a few ways how one could go about searching delimited text.

Two easy ways

Two easy ways

The easiest way to know if a certain item exists in a delimited list is the "is among" operator.

on mouseUp		
   put "random,list,of,items,that,have,no,particular,order" into theList
   put "no" is among the items of theList --true	
end mouseUp

I am not setting the itemdelimiter, because by default the itemdelimiter is always set to comma (,). But of course you could set it to tab, and then use it for a table field (or any other character you like).

Of course this doesn't really find the actual item, because it only tells me whether an item exists. Luckily, that often doesn't matter, because I might only want to know if an item exists, and not where exactly in an unordered list it appears.

Another way is to use the find command (see example in image above). For using find in delimited lists, it's a good idea to include the delimiter at the end or beginning. Find allows me to see where an item is in a field, but of course I can't use that position in code or do further work with it, because the find command only offers a visual search result.

Offsetting results

Offsetting results

When I am interested in where within a text a chunk appears, then can I use the offset functions. The offset, itemoffset, wordoffset and lineoffset functions all work the same way, so I will make examples that use them interchangeably.

To just show the position of an item in a field, I can use the following code:

on mouseUp
	select item itemoffset("foo", field 1) of field 1	
end mouseUp

This example behaves very similarly to the find command, but now the text is selected, and I could for example replace the selection with another text.

The result of the itemoffset function will be 0 (zero) when the searched term is not in the container. So in my example, if "foo" is not in the field, the insertion point will be put before the first char of field 1.

Extra feature: By default, LiveCode only returns the number of the first item that contains "foo". So the itemoffset example above would tell me "1", even if the first item in the field is "bazfoobar". To find items that match a search term exactly, I'd have to set the wholeMatches to true.

Attention: Make sure to read each of the chunk type descriptions in the dictionary. Some of them have specific behaviors, which are normally not applied that way (like something between quotes being just one word, no matter how many spaces there are).

Rows of trouble

Rows of trouble

Up to now we only wanted to find a specific term once. But what if we have lots of occurrence of an item, and want to know the position of each of them?

For this, the offset functions all have an optional third parameter, which I can set to where the offset should start. Let me show an example text:

abc

ab

c

So if I want to know where "c" is, but skip the first occurrence, I could say:

	put lineoffset("c", myList,1) -- will be 2 for the above example

Now maybe you'd say it should be 3, and I'd agree with that. But offset is a bit special, as it factors your specified skipping value into its return value. Although the "c" is on line 3, lineoffset returns 2 if you specify a skip value of 1 (2 + 1 equals the 3 we were actually looking for).

To get every item in a comma delimited list that contains "c", I made the following example code. Note how I use the value returned by the function to find the next "c" (within the repeat loop).

on mouseUp
	put itemoffset("c", field 1) into theValue
	put theValue & comma into theResult
	repeat forever
		put itemoffset("c", field 1,theValue) into newValue
		if newValue = 0 then
				-- all done!
				exit repeat
		end if
		add newValue to theValue
		put theValue & comma after theResult
	end repeat	
	delete char -1 of theResult -- remove trailing comma	
	put theResult
end mouseUp

But frankly, all the return values, and parameters, and strange use of repeat forever make my head spin. That is why I normally use this following code, when I want to find every occurrence of an item. It does exactly the same as the code above, just in a completely different way.

on mouseUp
	put itemoffset("c", field 1) into theValue
	if theValue <> 0 then
		repeat for each item currentItem in field 1
			add one to myCounter
			if currentItem contains "c" then -- with "wholematches": if currentItem is "c" then
				put myCounter & comma after theResult
			end if
		end repeat
	end if
	delete char -1 of theResult
	put theResult
end mouseUp

2 Comments

A Viescas

Nice, but it doesn't search for all matching strings, just the exact string in the file. (at least according to the documentation for "is among"). Finding a different matching string seems to require a loop and the "contains" operator.

Hanson Schmidt-Cornelius

Hi Viescas,

LiveCode has a number of text processing and matching features.
You can test for regular expressions with "matchText" or "matchChunk".
You can also specify if the search should look for entire lines, words or items using "wholeMatches".

The "See Also" category in the dictionary for the aforementioned entries also points you at a range of other search terms that may be useful for you.

Kind Regards,

Hanson

Add your comment

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.