if var in/contains comma-separated list/array

Discuss the future of the AutoHotkey language
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: if var in/contains comma-separated list/array

23 Sep 2018, 06:50

- This is the one important AHK v2 issue I've seen without an easy solution.
- These are my 2 best solutions at present, please be mature about any feedback.
- If you specify 1 needle for contains/in, it should be relatively easy to add a 2nd needle without rewriting everything.

Code: Select all

;IDEA 1: xxxC/xxxP operators

if (var contains StrSplit("abc,def,ghi", ",")) ;we need *SOMETHING* better than this
if (var contains "item1,item1ctd,item1ctd") ;1 item
if (var containsC "item1,item2,item3") ;3 items (no special ',,' handling)
if (var containsP "item1|item2|item3") ;3 items (no special '||' handling)

;contains, containsC, containsP
;in, inC, inP
;starts, startsC, startsP ;potentially
;ends, endsC, endsP ;potentially

;note: the xxxP operators are useful for needles that contain commas and for conversion to/from ~= (RegExMatch)

;==================================================

;IDEA 2: StrSplit comma/pipe unary operators

if (var contains StrSplit("abc,def,ghi", ",")) ;we need *SOMETHING* better than this
if (var contains "item1,item1ctd,item1ctd") ;1 item
if (var contains splitc "item1,item2,item3") ;3 items (no special ',,' handling)
if (var contains splitp "item1|item2|item3") ;3 items (no special '||' handling)

;note: perhaps a 'split' or 'splitx' operator would split every character (n-length string to n-length array)

;note: alternatively/additionally, a binary operator: "a,b,c" split "," [although this puts the operator after the string, where it's less visible, and easy to miss]
;[EDIT:] if (var contains "abc,def,ghi" split ",") [not great, less clear than StrSplit()]
Last edited by jeeswg on 23 Sep 2018, 10:49, edited 1 time in total.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
guest3456
Posts: 3453
Joined: 09 Oct 2013, 10:31

Re: if var in/contains comma-separated list/array

23 Sep 2018, 10:36

there are function and regex alternatives in this thread:

https://autohotkey.com/boards/viewtopic ... 37&t=23033

using a C/P suffix is awful

User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: if var in/contains comma-separated list/array

23 Sep 2018, 10:45

- Thanks for your response.
- I'd want something built-in, so that scripts can be easily shared. So no custom functions.
- RegEx is slow. (Although is StrSplit slower? I'll do some benchmark tests.)
- RegEx requires character escaping.
- RegEx requires fiddly ^, $ and parenthesis adding.
- RegEx handles string comparisons only. The 'in' operator might support handling for numeric comparisons.
- So StrSplit is the best existing option.

- I would really appreciate if people think about this problem, and try to come up with any syntax suggestions. I do find this question a tricky one.
- Another idea would be something like: var match "X,)abc,def,ghi". That would check for an exact match, comma-delimited. A kind of home-grown simpler RegEx for C/E/S/X (contains/ends/starts/exact).
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
guest3456
Posts: 3453
Joined: 09 Oct 2013, 10:31

Re: if var in/contains comma-separated list/array

23 Sep 2018, 18:15

jeeswg wrote: - I'd want something built-in
then there is nothing to talk about. either build it in yourself and submit a pullrequest, or wait for lexikos to build it in
jeeswg wrote:so that scripts can be easily shared. So no custom functions.
just include your custom function in the script and it can be easily shared.

User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: if var in/contains comma-separated list/array

23 Sep 2018, 19:21

- The point of this forum is to *talk about* *built-in* functionality.
- We don't have a consensus here, so no pull requests from me.
- Like with the command/function syntax 6-year debate, people here have complained but offered nothing, delaying a decision.
- FWIW I'd say: string = 1 item, array = multiple items, that's enough for a working operator. I await ideas on haystack arrays and delimiter-separated lists.

- Re. 'easily shared'. Ideally, basic functionality should be newbie-friendly. So, no duplicate function errors, or differing functions with the same name, or 10 versions of the same function.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
User avatar
kczx3
Posts: 1640
Joined: 06 Oct 2015, 21:39

Re: if var in/contains comma-separated list/array

23 Sep 2018, 19:39

I’d rather a method on the string and object prototypes like JavaScript than using a keyword anyways
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: if var in/contains comma-separated list/array

23 Sep 2018, 19:52

Interesting point. I was trying so hard to come up with a good idea, I even thought of using an operator together with a method on a string:
if var contains "abc,def,ghi".split(",")
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
iseahound
Posts: 1427
Joined: 13 Aug 2016, 21:04
Contact:

Re: if var in/contains comma-separated list/array

24 Sep 2018, 20:03

Sorry, what's wrong with if var contains "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"
which is parsed as if var.contains("Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun")

As I understand it, contains is a function which takes any number of variables. (variadic)
and contains is a method of var.

Caveats:
Another example: Say I have the following in my code:

Code: Select all

if(foo contains bar) { ..
Say, I need to negate the condition. If I modify it as follows:

Code: Select all

if(!foo contains bar) { ..
Bummer. This gets parsed as (!foo).contains(bar). Not what we wanted.

Or suppose you need to add a new condition in addition, and you modify it so:

Code: Select all

if(foo contains bar && cond) { ..
Another bummer. This gets parsed asfoo.contains(bar.&&(cond)). Not what we wanted, again.

Of course, you could add a bunch of parentheses around, but that would be ugly and hard to read/edit as compared with dot notation.

Now, all of what I said above applies to symbolic method names too. However symbolic methods look unnatural when used with dot syntax, and so I prefer the infix syntax for them.
Source: https://stackoverflow.com/questions/102 ... t-notation
User avatar
nnnik
Posts: 4500
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: if var in/contains comma-separated list/array

25 Sep 2018, 01:24

I don't want to add special features for comma separated lists. No argument you have to offer can change my mind about this.

@iseahound
Sadly our "," already has a specific meaning so this Form of calling won't be possible. Also contains is an operator rather than a method call.
Recommends AHK Studio
lexikos
Posts: 9494
Joined: 30 Sep 2013, 04:07
Contact:

Re: if var in/contains comma-separated list/array

25 Sep 2018, 06:29

"not in" and "not contains" are a possibility. Python has "is not".
iseahound
Posts: 1427
Joined: 13 Aug 2016, 21:04
Contact:

Re: if var in/contains comma-separated list/array

25 Sep 2018, 10:42

nnnik wrote:Also contains is an operator rather than a method call.
There is an equivalence between operators and methods.

Code: Select all

2 + 3
2.+(3) ; strange but should be valid
which seems strange. But consider this code:

Code: Select all

object.push("dog", "cat")
object push "dog", "cat"
which should be command syntax for object methods.

To parse everything correctly:

Code: Select all

obj push "dog", "cat"
obj(push("dog", "cat")) ; obj is not a function and does not take arguments. 
obj.push("dog", "cat") ; try invoking a method of obj. 
So this is the sort of radical change I'd like to see in v2. It would do 3 main things.
- Settle the Command vs. Function syntax argument once and for all by allowing both commands and functions to have the same expressiveness.
- Formalize operators like contains, such that operators are in some sense global methods, and object methods are by default limited to that object
- Allow operator overriding.

I took inspiration from here: https://docs.scala-lang.org/style/metho ... ation.html

EDIT: I made a separate thread https://autohotkey.com/boards/viewtopic ... 37&t=56294
User avatar
nnnik
Posts: 4500
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: if var in/contains comma-separated list/array

25 Sep 2018, 11:24

operators are not methods in AHK. And Strings cannot have string specific methods yet.
Recommends AHK Studio
iseahound
Posts: 1427
Joined: 13 Aug 2016, 21:04
Contact:

Re: if var in/contains comma-separated list/array

25 Sep 2018, 11:30

There exists a duality between operators and methods.

See operator overriding in Python: https://thepythonguru.com/python-operator-overloading/
which is a bit of a mess, since they define __add__ to be a meta function to represent +
User avatar
nnnik
Posts: 4500
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: if var in/contains comma-separated list/array

25 Sep 2018, 12:16

The possibility exists. But not in AHK - at least not yet.
Recommends AHK Studio
User avatar
nnnik
Posts: 4500
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: if var in/contains comma-separated list/array

25 Sep 2018, 17:35

I doubt that will happen in v2.
Recommends AHK Studio
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: if var in/contains comma-separated list/array

04 Nov 2018, 21:50

Anyhow, methods applied to strings are already possible.

Code: Select all

;Objects
;https://hotkeyit.github.io/v2/docs/Objects.htm
;When a non-object value is used with object syntax, the default base object is invoked. This can be used for debugging or to globally define object-like behaviour for strings, numbers and/or variables. The default base may be accessed by using .base with any non-object value; for instance, "".base. Although the default base cannot be set as in "".base := Object(), the default base may itself have a base as in "".base.base := Object().

q:: ;methods applied to strings
"".base.base := {len:"StrLen", split:"StrSplit"}

vOutput := ""
for vKey, vValue in "a,b,c".split(",")
	vOutput .= vKey " " vValue "`r`n"
MsgBox, % vOutput

vText := "a,b,c"
vOutput := ""
for vKey, vValue in vText.split(",")
	vOutput .= vKey " " vValue "`r`n"
MsgBox, % vOutput

vText := "abcdefghijklmnopqrstuvwxyz"
MsgBox, % vText.len()
MsgBox, % "abcdefghijklmnopqrstuvwxyz".len()
return
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
iseahound
Posts: 1427
Joined: 13 Aug 2016, 21:04
Contact:

Re: if var in/contains comma-separated list/array

15 Nov 2018, 22:33

Yeah that's why I liked my suggestion of making things methods operators.

Code: Select all

; Define a method that works on the String class.
"".base.contains := Func("Contains")

Contains(state, terms*) {      ; state means internal state. In an AHK object, it would be called "this", and is implicit (does not need to be the 1st parameter).
   for index, word in terms    ; terms contains our comma separated values (CSV).
      if (state ~= word)       ; ~= is short hand for RegExMatch().
         return word           ; return the matching word instead of a Boolean (true).
}

MsgBox % "Jumpy zebra vows to quit thinking coldly of sex.".contains("zebra")
MsgBox % "Jumpy zebra vows to quit thinking coldly of sex.".contains("deer", "cobra", "lion")
It wouldn't do anything to the code other than changing how it is parsed. I wish the following would work:

Code: Select all

MsgBox % "Jumpy zebra vows to quit thinking coldly of sex." contains ("zebra")
which looks nicer in an if statement

Code: Select all

if ("Jumpy zebra vows to quit thinking coldly of sex." contains ("zebra"))
   return true
we could even even have a rule where if there is only one argument, the parenthesis could be omitted:

Code: Select all

if ("Jumpy zebra vows to quit thinking coldly of sex." contains "zebra")
   return true
if ("Jumpy zebra vows to quit thinking coldly of sex." contains ("deer", "cobra", "lion")) ; Multiple arguments in parenthesis!!!!
   return true
There is the idea of prefix, infix, and postfix notation in some languages. Haskell? If you have a simple function such as Add(x, y), you could remove the parenthesis first. This resembles command syntax in AHK v2. Add x, y Now this is called prefix notation because the function is before the arguments. Infix notation would be x add y. This is more natural if the function is symbolic like x + y. However, in Haskell, the function name can only be placed between the first and second arguments. So Add x, y, z could potentially become x Add y z. I think this is confusing so I would recommend that we keep the AHK way of comma separation and force multiple arguments to be wrapped in parenthesis and comma separated like x Add (y, z). I think this is how Scala does this.
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: if var in/contains comma-separated list/array

22 Apr 2019, 11:29

The issue of how to handle a comma-separated list is back.
This time for InputHook's MatchList parameter:
"abc,def,ghi" [currently 3 items, not 1 item]
",," [currently a literal comma, not 3 blank items, not 1 item]

Test build - InputHook, long paths, switch-case - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=24&t=63861
Input - Syntax & Usage | AutoHotkey
https://autohotkey.com/docs/commands/InputHook.htm#comparison

I have no particular desire to debate this any further, however, if you want to say something re. Input/InputHook/in/contains, and how literal strings are handled, you'd better say it now, before it becomes set in stone for AHK v2.
If pushed, I'd have to say: a literal string should always be treated as one item. But, having to use arrays for multiple items introduces verbosity, and so there's no easy answer.

Are there other places where comma-separated lists are present in AHK?

[EDIT:] For reference, Explorer's SortColumns property uses a semicolon-separated list, so, delimiter-separated lists are not unheard of.
jeeswg's Explorer tutorial - AutoHotkey Community
https://www.autohotkey.com/boards/viewtopic.php?f=7&t=31755

[EDIT:] At this point, I'm not so bothered how in/contains will handle strings, be it string = 1 item (consistency), or string = comma-separated list (convenience), I'll trust the devs to make the decision.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: if var in/contains comma-separated list/array

27 Oct 2019, 12:35

To move on, I'd say: 1 string is always 1 item. And if you want 1 string treated as a comma-separated list, you can write your own function, like so:

Code: Select all

if var contains "abc,def,ghi" ;1 literal string

if var contains ["abc", "def", "ghi"] ;3 strings

if MyContainsCSL(var, "abc,def,ghi") ;3 strings

MyContainsCSL(var, list)
{
	if IsObject(list)
		return (var contains list)
	return (var contains StrSplit(list, ","))
}
Potentially a built-in StrContains function could accept 'D,' to have a comma-separated list, but for the foreseeable future I'd be happy with the above.
(The same principles would apply to 'in', MyInCSL/MyEqualsCSL and a potential StrEquals function.)

(I know that = and 'in' would be similar, however, 'in' could be made case sensitive.)
(I know that InStr and 'contains' would be similar, however, it's often convenient to write all statements in an if/else ladder consistently, using either a function or an operator.)
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA

Return to “AutoHotkey Development”

Who is online

Users browsing this forum: No registered users and 28 guests