LiveCode LessonsHow To - Step-By-Step Guides To Tasks In LiveCode TextHow can I search delimited data for a matching string?

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 similar 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 behaviours, 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'd 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 then the 3 we where 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

E-Mail me when someone replies to this comment