1

When using the operator ⎕S in Dyalog APL I'm only interested in if there is a match or not, so the expression

('foo' ⎕S F) 'foo' 'bar' 'foofoo'

should evaluate to

.→----.
|1 0 1|
'~----'

What function (or string) F will achieve this?

Edit: The example is just to illustrate the point. In practice the regular expression can be much more complicated.

August Karlstrom
  • 10,773
  • 7
  • 38
  • 60

2 Answers2

1

Disclaimer

⎕S is a powerful beast with many capabilities - but I'm not sure it is the right tool for such a simple job as checking if there is a match or not. But maybe you tried to simplify a complex problem - or maybe I'm not understanding ⎕S well enough. So I'd like to show how I would solve the given problem and will then look potential ⎕S-approaches.

Find

Find returns a boolean vector with ones at the starting position of the searched string. So I'd a find in each of the vectors and then an ∨/(or-reduce) to determine if there is a match:

      ∨/¨'foo'∘⍷¨'foo' 'bar' 'foofoo' 
1 0 1

⎕S

With ⎕S, you can search using regex even on a nested argument. So we'll need to use the each-operator ¨ to apply ⎕S f on each of the 3 vectors.

   {('foo'⎕S f)⍵}¨'foo' 'bar' 'foofoo' 

Then there are various things it could return:

  • the lengths of any matches: using f=tranformation-code 1, it would return the length of the matching strings. Since we have a fixed pattern, it would be any number of 3s (zero to n). In your example:
    {('foo'⎕S 1 )⍵}¨'foo' 'bar' 'foofoo' 
    
┌─┬┬───┐
│3││3 3│
└─┴┴───┘

Finally, check if we have any 3s, and we have the desired result:

      3∊¨{('foo'⎕S 1 )⍵}¨'foo' 'bar' 'foofoo' 
1 0 1
  • the matching string itself. Using transformation patter &, it would return the matching string:
    {('foo'⎕S '&' )⍵}¨'foo' 'bar' 'foofoo' 
┌─────┬┬─────────┐
│┌───┐││┌───┬───┐│
││foo││││foo│foo││
│└───┘││└───┴───┘│
└─────┴┴─────────┘

Check if there are matches and we're done:

     0<≢¨{('foo'⎕S '&' )⍵}¨'foo' 'bar' 'foofoo' 
1 0 1
  • and finally, just to cover that one, too - with a transformation function. The TF is called for each match that was found is is passed a namespace with various fields describing the match. (The help documents the various possibilities, I'm going to use .Lengths which gives the same a transformation-code 1 in the earlier example)
      {('foo'⎕S {⍵.Lengths} )⍵}¨'foo' 'bar' 'foofoo' 
┌───┬┬─────┐
│┌─┐││┌─┬─┐│
││3││││3│3││
│└─┘││└─┴─┘│
└───┴┴─────┘
      0<≢¨{('foo'⎕S {⍵.Lengths} )⍵}¨'foo' 'bar' 'foofoo' 
1 0 1

Actually, we don't need Lengths at all - we can just check if it gets any calls:

      ∨/¨{('foo'⎕S {0<≢⍵} )⍵}¨'foo' 'bar' 'foofoo' 
1 0 1

The end

I hope this gives you a few ideas :)

Community
  • 1
  • 1
MBaas
  • 7,248
  • 6
  • 44
  • 61
1
      (≢'foo'⎕S 3⍠'ML'1)¨'foo' 'bar' 'foofoo'
1 0 1

What is happening here?

⎕S 3 returns the pattern which matched in 0-origin (so that'll always be 0 if you only have a single pattern)

⍠'ML'1 sets the Match Limit to 1, so ⎕S won't keep searching an element after finding the first match. This ensures that each result has at most one element, and also improves performance by not searching further when we already know enough — that there is a match.

( is necessary because we must search each character vector separately. If we just wanted to know whether the pattern occurred anywhere in the document, we didn't need this.

counts the number of pattern indices in each result. Since we set a Match Limit, each result will be either a 1-element vector (if found) or a 0-element vector (if not found), and so our overall result will be the Boolean vector we wanted.

Try it online!


It is worth noting that ⎕S will analyse your search pattern and if the search does not require regular expressions, it will use a much faster search algorithm, so you can rely on ⎕S without worrying about needing to use for optimal performance of simple patterns.

Adám
  • 6,573
  • 20
  • 37