Programmatically discern strings to be titles vs filters?

Yes, I know, titles are a form of filter. But, I need to programmatically be able to discern if a field value is a filter or a title/titles.

Currently I’m peeking at the initial characters of the string - if it is prefixed with a single [ then it’s interpreted as a filter. If it is prefixed with [[ or no bracket, then it is/are title/s. That strategy is not sure-fire; a title can, hypthetically, include a string prefixed with [ and a filter needs more stuff than just a [[ prefix. But the context for this all is pretty forgiving and things happen “out in the open” as one types the string, so it is pretty obvious if something goes wrong.

So I’m wondering if there is a better - yet still simple - method to discern if a string is a filter or not. For example, there may be some nifty regexp for it? Some hidden core function? Or just some tiddlenious method… :slight_smile:

One Approach I use, it to alter my macros to treat the parameter as a filter, which will be treated as a list of titles if it is. Because often a list of titles is just a simplified filter any way.

  • Never the less I will give it some more thought.
1 Like

Hi Mat,

There are certainly cleaner solutions, but here is a function that compares the results of

  1. the input string interpreted as a filter and
  2. the same input string interpreted as a list of titles.

When the input string is a list, both results are the same. If not, we get 2 different results. Give it a try on tiddlywiki.com:

\function list.or.filter?(string) 
[<string>] :map:flat[subfilter<currentTiddler>format:titlelist[]] :and[join[ ]] 
[<string>enlist-input[]format:titlelist[]join[ ]] 
:and[count[]match[2]then[filter]else[list]]
\end

{{{ [[Cascade Filter Run Prefix (Examples)]get[filter1]] :map[list.or.filter?<currentTiddler>] }}} 
should return ''filter'' 
while
{{{ [[Cascade Filter Run Prefix (Examples)]get[filter3]] :map[list.or.filter?<currentTiddler>] }}} 
should return ''list''.
2 Likes

Oh man, thank you @xcazin ! That construct is way beyond what I could have made myself. I barely understand it even looking at it. Thank you!

I find this request interesting so looked a little closer and came up with this;

\define open() [
\define open-title() [[
\define saved-filter() [all[current]] [tag[TableOfContents]]
\function is.filter.string(string) [<string>prefix<open>!prefix<open-title>!prefix<open-title-op>then[filter]] :else[subfilter<string>count[]addsuffix[ title(s)]]

# <<is.filter.string "HelloThere nothis">>
# <<is.filter.string "[title[HelloThere]] nothis">>
# <<is.filter.string "nothis [title[HelloThere]]">>
# <<is.filter.string "[[HelloWorld]]">>
# <<is.filter.string "[all[current]] [tag[TableOfContents]]">>
# {{{ [is.filter.string<saved-filter>] }}}
  • Test if string begins [ but not [[ assume its a filter and return filter
    • Subsequently extended to treat [title[ as a title not a filter.
  • Now for all others treat it as a subfilter and count and return that.
  • use it as a filter operator as well, example 6

Special note;
This words differently if “saved-filter” is a function rather than a macro as above

I am not sure how exhastive it would be and how it may be tricked.

  • I cant think of a way to trick it.
  • however there is not harm always treating it as a filter, because a title or title list is also a filter.

Futures;

  • I think this can be simplified further.

Right that is pretty much the algo I used too but which I think is too brittle. I don’t think it is enough to look at “bracket prefix configurations” to make the distinction, for example [[foo]prefix[f]] is arguably a filter.

This is why my preferred approach is to treat*** titles, title lists and filters*** all as filters, if there is any chance the parameter value is any of these.