Meaning of :pick parameters for strings?

I’m at RouterOS 6.35.1 and not sure if I should upgrade to 6.35.2 given the number of bugs mentioned there.

There seems to be something odd with :pick parameters on strings.

From the from the documentation:

  1. Command pick
  2. Syntax :pick []
  3. Description return range of elements or substring. If end position is not specified, will return only one element from an array.
  4. Example :put [:pick “abcde” 1 3]

I’d expect both the start and end parameters to be both based on either the first character of a string at position zero or at position one.

It looks however that the start parameter assumes the first character to be at position zero, but the example from the documentation returns only two characters where I expected three:

[admin@MikroTikCCR1009] > :put [:pick "abcde" 1 3]
bc

What am I missing here?

To elaborate on my suspicion, I created more test cases.

Only a start parameter: it indicates position zero is the start of the string and four the end of the string. Position five is beyond the end of the string.

[admin@MikroTikCCR1009] > :put [:pick "abcde" 0]
a
[admin@MikroTikCCR1009] > :put [:pick "abcde" 1]
b
[admin@MikroTikCCR1009] > :put [:pick "abcde" 2]
c
[admin@MikroTikCCR1009] > :put [:pick "abcde" 3]
d
[admin@MikroTikCCR1009] > :put [:pick "abcde" 4]
e
[admin@MikroTikCCR1009] > :put [:pick "abcde" 5]

The end parameter however behaves strangely as all these should have returned a string with one character:

[admin@MikroTikCCR1009] > :put [:pick "abcde" 0 0]

[admin@MikroTikCCR1009] > :put [:pick "abcde" 1 1]

[admin@MikroTikCCR1009] > :put [:pick "abcde" 2 2]

[admin@MikroTikCCR1009] > :put [:pick "abcde" 3 3]

[admin@MikroTikCCR1009] > :put [:pick "abcde" 4 4]

[admin@MikroTikCCR1009] > :put [:pick "abcde" 5 5]

Being a programmer by trade, I guessed an off-by one error and that indeed seems to be the case, as all these return exactly one letter except for the last one (as five is beyond the string when using zero based indexing and six is beyond the string for one based indexing).

[admin@MikroTikCCR1009] > :put [:pick "abcde" 0 1]
a
[admin@MikroTikCCR1009] > :put [:pick "abcde" 1 2]
b
[admin@MikroTikCCR1009] > :put [:pick "abcde" 2 3]
c
[admin@MikroTikCCR1009] > :put [:pick "abcde" 3 4]
d
[admin@MikroTikCCR1009] > :put [:pick "abcde" 4 5]
e
[admin@MikroTikCCR1009] > :put [:pick "abcde" 5 6]

This seems to cofurm that end is indeed the finishing position (at d the wrong one, but at least they are consistently using d):

[admin@MikroTikCCR1009] > :put [:pick "abcde" 0 4]
abcd
[admin@MikroTikCCR1009] > :put [:pick "abcde" 1 4]
bcd
[admin@MikroTikCCR1009] > :put [:pick "abcde" 2 4]
cd
[admin@MikroTikCCR1009] > :put [:pick "abcde" 3 4]
d
[admin@MikroTikCCR1009] > :put [:pick "abcde" 4 4]

[admin@MikroTikCCR1009] > :put [:pick "abcde" 5 4]

But using five instead of four gives the expected strings ending with character e:

[admin@MikroTikCCR1009] > :put [:pick "abcde" 0 5]
abcde
[admin@MikroTikCCR1009] > :put [:pick "abcde" 1 5]
bcde
[admin@MikroTikCCR1009] > :put [:pick "abcde" 2 5]
cde
[admin@MikroTikCCR1009] > :put [:pick "abcde" 3 5]
de
[admin@MikroTikCCR1009] > :put [:pick "abcde" 4 5]
e
[admin@MikroTikCCR1009] > :put [:pick "abcde" 5 5]

–jeroen

What’s the question here? You seem to have figured it out already… The strings are zero based, the “end” is indeed “end”, relative to the input, not relative to “start”, and out of range values are (in effect) truncated to the nearest valid one.

Is end indeed the number of characters, or is it just using 1-based indexing?

I need to think about examples proving either of these.

–jeroen

It is zero based index of the string, relative to the beginning of the input. The string is cut at that point, meaning that all characters BEFORE that point are included, NOT including the character itself.

e.g.

:put [:pick "abcde" 1 3]

outputs “bc”.

Because “a” is 0, “b” is 1, disregarding “end” for a moment, we have “bcde” included in the result.

Then with the “end”, “c” is 2, and “d” is 3, so all characters before “d” are “abc”.

The intersection between “bcde” and “abc” is “bc”, so that’s what the result ends up as.

Is it possible to pick from a point to the end?

more likely this:

:foreach limited in=[/queue simple find max-limit~"1024k"] do={
:local customerusername [/queue simple get $limited name]
:pick [ $customerusername 8 to end ] }

???
Thanks!

Use “:len $str” as a 3rd argument, or in your particular example:

:foreach limited in=[/queue simple find max-limit~"1024k"] do={
:local customerusername [/queue simple get $limited name]
:put [:pick $customerusername 8 [:len $customerusername]] }

Nice! Thanks… sure, that logic should do.
Just another question, what about pick until a chracter apears ?
For example:
Our routers are named related to a Point of Distribution.
Identity = “POP NAME” (space) ROUTERNAME
So, if I want to send a backup over FTP, and put the backup on a folder that only has the POP name, how can I pick until space apears, since the POP name are not with same lenght?
THANKS!!!

I got it:

:local something [:pick [/system identity get name] 0 [:find [/system identity get name] " " -1]]