logical "or" over number

Hello !

What is the easiest way to perform a logical or script operation on a number represented by a string variable? For example, there is a line “01001”. Should it be converted to “10110”?

I answer myself:

{
:local a "1101"
:local c
:for i from=0 to=[:len $a] do={:set c ("$c"."$[:pick $a $i (1+$i)]".".")}
:set $c [:pick $c 0 ([:len $c]-2)]
:put $c
:set c ($c^1.1.1.1)
:put $c
}

but this only works with 4 digits.

This can be done in blocks of 4 digits to the end. In the example for 5 digits:

# inversion for 5 digits
{
:local a "10011"; :local b; :local d
:local f do={:local c; :for i from=0 to=[:len $1] do={:set c ("$c"."$[:pick $1 $i (1+$i)]".".")}; return [:pick $c 0 ([:len $c]-2)]}
:set b ([$f [:pick $a 0 4]]^1.1.1.1); :set d ([$f [:pick $a 1 5]]^1.1.1.1); :set d ("$b"."$[:pick $d 5 7]"); set b ""
:for i from=0 to=[:len $d] do={:set a [:pick $d $i (1+$i)]; if ($a=".") do={} else={:set b ("$b"."$a")}}
:put $b
}

Maybe Rex will laugh and it can be much simpler and shorter? More versatile ?

The built-in bitwise XOR:
https://wiki.mikrotik.com/wiki/Manual:Scripting#Bitwise_Operators
should work also for IPv6 and num data types:

Bitwise Operators

Bitwise operators are working on number, IP and IPv6 address data types.

So, using your code but with IPv6 (and : instead of . as separator) you should be able to get at 8 digits.

Otherwise you would probably need to convert the binary to num, and then the result back to binary, rextended has posted:
http://forum.mikrotik.com/t/rextended-fragments-of-snippets/151033/18
http://forum.mikrotik.com/t/rextended-fragments-of-snippets/151033/18

The proposed options are not shorter than mine… We need to write a function that XORs a binary number of any length.
Where did our Cat go? :smiley:

The topic is wrong at the start.
Then it’s not even written, but I suppose they are binary numbers…
OR and XOR are operation between two bit/number.

Then in the second post an IP number pops up… (1.1.1.1)
This topic starts badly and its meaning is not clear…

Anyway:
(000)01001 XOR (000)11111 = (000)10110

Even negation must be handled according to significant figures…

NOT 01001 is wanted = to 10110 ???, so NOT 9 = 22 ???
but…
NOT (000)01001 is = to (111)10110 so NOT 9 = -9 ???


Since RouterOS do not work with binary data, and you want work with strings,
simply search and replace 1 on 0 and 1 with 0 on string…

I get @Sertik like a clean simple generic solution. But… once you go beyond 7-bits, all conversions from binary to number need to know a lot more on how the binary is structured. If you really are starting with some LONGER string with binary 1/0’s like “01000100101111010101010” — you have to also know the original byte ordering (and endian-ness etc) to get that to a number (and then routeros has a limit on it’s int size too).

In 7.16, there are new :convert operators, including a “bit-array-xxx”, that help do the reverse:

:put [:convert from=hex to=bit-array-lsb "EF"] 
# 1;1;1;1;0;1;1;1
:put [:convert from=hex to=bit-array-msb "EF"] 
# 1;1;1;0;1;1;1;1
:put [:convert from=byte-array to=bit-array-lsb {239}]   
# 1;1;1;1;0;1;1;1
:put [:convert from=byte-array to=bit-array-msb {239}]      
# 1;1;1;0;1;1;1;1

But the it’s only a one-way to bits, as there is no from=bit-array-XXXX which make sense since again once past 8-bit, the conversion needs to know more beyond LSB and MSB :wink:. That, and, the new commands were designed around the data coming from IoT things like Bluetooth - where you’d want to parse the binary payload - but IoT starts with a hexstring so all the :convert operators are built around the “hexstring” (“FF00EE”) as the starting point for these byte/bit conversions.

Just one example on the string, but obviously my previous post it wasn’t that rich in explanations, but it highlights the lack in what was being written…
{
:local invert01onstr do={
:local result “”
:for i from=0 to=([:len $1] -1) do={
:if ([:pick $1 $i (1 + $i)] = “1”) do={:set result ($result . “0”)} else={:set result ($result . “1”)}
}
:return $result
}

:put [$invert01onstr “10011”]

:put [$invert01onstr “1010110011”]

:put [$invert01onstr “010”]
}
01100
0101001100
101

@Amm0 It would be easier to know where that 01001 came from and why it needs to be transformed into 10110.

But @Sertik suckers us in every time. I guess I view his questions a RouterOS version of LeetCode questions (i.e. theoretical CS problems).

Anyway, for fun, here is my take:
:global invBinaryString do={
:local bstr $1
:local asString false
:if ($2 = “as-string”) do={:set asString true}
:local barr [:toarray “”]
:for i from=0 to=([:len $bstr]-1) do={:set ($barr->$i) (![:tobool [:tonum [:pick $bstr $i ($i+1)]]])}
:if $asString do={
:local xorstr “”
:foreach b in=$barr do={
# bool->num not possible - :set xorstr “$xorstr$[:tonum $b]”
:if $b do={ :set xorstr ($xorstr . “1”) } else={:set xorstr ($xorstr . “0”) }
}
:return $xorstr
} else={
:return $barr
}
}
:put [$invBinaryString “1010101111101”]

false;true;false;true;false;true;false;false;false;false;false;true;false

:put [$invBinaryString “1010101111101” as-string]

0101010000010

Do not do the same error, is not a OR or XOR, the number is only one, is just INVERT or at least NOT (can not really be NOT since the base is unknow…)

I wrote it that way and named it wrong. :open_mouth: As you point out, it hard to know what he’s looking for. I was just trying to point out getting to array make using the bits-in-string easier (and that allow the :convert stuff if desired). i.e. once converted, you’d still likely want to access the bits inside & array makes that easy:

:global invbits [$invBinaryString "1010101111101"]          
:put ($invbits->0)                               
#false

And correct if a real OR and/or XOR is needed, more info be needed.

Also, there be another approach using ":convert to=byte-array"to get an array… but that get you the ASCII codes for 1 and 0

:put [:convert to=byte-array from=raw "10101010"]
# 49;48;49;48;49;48;49;48

but since that’s at least an array, and not a string, you can use a :foreach on it.

Anyway…the underlying complexity stems from that strings are not arrays in RouterOS. So the stupid :for and [:pick], [:len], etc. to deal “read a char” from a string are needed. e.g. (“mystring”->0) does NOT work nor get you “m”.

So the sooner you get some bit/num/byte things to an array, the better… all the conversion like OR or whatever become easier.

Firsto obstacle on OP is arbitrary lenght. Can happen. A byte can contain various information in specific points. For example:

0 0 0 = 0
0 0 1 = 1
0 1 0 = 2
0 1 1 = 3
1 0 0 = -4
1 0 1 = -3
1 1 0 = -2
1 1 1 = -1

Or simply none are negative, is from 0 to 7 (or from 1 to 8..)

Probably you want write another thing… :wink:

:put [:convert to=byte-array from=raw "\01\00\01\00\01\00\01\00"] 
# 1;0;1;0;1;0;1;0

And we come back to the original problem… How did those bits get represented in a RouterOS string – those had to come from somewhere. So if it was already “\01\00” form, not a string with actual ascii… then everything is easier.

Without any concrete needs/use, are all useless.

{
:local invert01onstr do={
    :local result ""
    :for i from=0 to=([:len $1] -1) do={
      :if ([:pick $1 $i (1 + $i)] = "1") do={:set result ($result . "0")} else={:set result ($result . "1")}
    }
    :return $result
}

This is what we need. Very simple and great! Thanks Rex!
God ! Why am I so dumb?

:global invBinaryString do={
   :local bstr $1
   :local asString false
   :if ($2 = "as-string") do={:set asString true}
   :local barr [:toarray ""]
   :for i from=0 to=([:len $bstr]-1) do={:set ($barr->$i) (![:tobool [:tonum [:pick $bstr $i ($i+1)]]])}
   :if $asString do={
     :local xorstr ""
     :foreach b in=$barr do={
        # bool->num not possible - :set xorstr "$xorstr$[:tonum $b]"
        :if $b do={ :set xorstr ($xorstr . "1") } else={:set xorstr ($xorstr . "0") }
     }
    :return $xorstr 
   } else={
      :return $barr
   }
}
:put [$invBinaryString "1010101111101"]
# false;true;false;true;false;true;false;false;false;false;false;true;false
:put [$invBinaryString "1010101111101" as-string]
# 0101010000010

Thank you very much for this too, Amm0!

But @Sertik suckers us in every time.

:smiley: Well, dear friend! No way…