Trying to understand txt2bin code from forum

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
User avatar
dmg
Posts: 287
Joined: 02 Oct 2013, 01:43
Location: "Twelve days north of Hopeless and a few degrees south of Freezing to Death"
Contact:

Trying to understand txt2bin code from forum

23 Oct 2015, 04:10

For fun I decided to write some functions to convert text to binary and back. To do this I first learned how to read/write in binary. That was oddly the easy part. Now I want to understand how I can do it using code. I looked at existing code on the forum and selected these functions to learn from:

Code: Select all

text := "I have no idea why this works, but it obviously does."
bin := txt2bin(text)
msgbox % "Txt:`n" text "`n`nBin:`n" bin "`n`nTxt:`n" bin2txt(bin)


txt2bin(txt)
 {
   loop parse, txt
    {
      loop 8
       {
         bin := bin (asc(a_loopfield) >> (8 - a_index) & 1)
       }
    }
   return bin
 }

bin2txt(bin)
 {
   loop parse, bin
    {
      x += x + (a_loopfield = "1")
      if !mod(a_index, 8)
       {
         txt := txt chr(x)
         x = 0
       }
    }
   return txt
 }
The problem is this code has elements I just don't understand. I can figure out in very general terms what the parts do, meaning the action they accomplish, but I have no idea exactly what they are doing or how they are doing it.

In the first function it is >> (8 - a_index) & 1) I am stumped on (I am not math literate). I know that >> is bitshift right, and & is bitwise-and, but knowing their names does not help me understand them.

In the second function the hardest part is x += x + (a_loopfield = "1") That is incrementing x by x +... Whatever that last bit is. That looks like it is assigning to a_loopfield, but a_loopfield is a built in variable and you can't assign to them, right? And what is = "1"? If it were := "1" I would say it was assigning a literal 1 character, but if I add : to it it breaks the code, so that's out. I have no reference point for that bit of code.

Anybody care to pick this code apart and explain it? I can't guarantee I will understand, but I promise to try
"My dear Mr Gyrth, I am never more serious than when I am joking."
~Albert Campion
------------------------------------------------------------------------
Website | Demo scripts | Blog | External contact
User avatar
dmg
Posts: 287
Joined: 02 Oct 2013, 01:43
Location: "Twelve days north of Hopeless and a few degrees south of Freezing to Death"
Contact:

Re: Trying to understand txt2bin code from forum

23 Oct 2015, 04:40

It certainly can't hurt. I will look through those and see. Thanks jNizM. :)
"My dear Mr Gyrth, I am never more serious than when I am joking."
~Albert Campion
------------------------------------------------------------------------
Website | Demo scripts | Blog | External contact
User avatar
jNizM
Posts: 3183
Joined: 30 Sep 2013, 01:33
Contact:

Re: Trying to understand txt2bin code from forum

23 Oct 2015, 04:47

or you let the dll's calc this for you :P
[AHK] v2.0.5 | [WIN] 11 Pro (Version 22H2) | [GitHub] Profile
just me
Posts: 9532
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Trying to understand txt2bin code from forum

23 Oct 2015, 05:44

Well, my attempt for txt2bin().

As a start, the parse-loop will only work properly for strings containing only characters which are represented by exactly one byte.

Each byte is composed of 8 bits. The bit positions are numbered from 0 to 7, where 0 is the position of the least-significant / rightmost bit, and 7 is the position of the most-significant / leftmost bit. Each bit can contain 0 or 1. Its value is the result of BitValue * 2**BitPosition, e.g 00000001 = 1 * 2**0 = 1, 00000010 = 0 * 2**0 + 1 * 2**1 = 2, 00000011 = 1 * 2** + 1 * 2**1 = 3, etc.

txt2bin():

bin := bin (asc(a_loopfield) >> (8 - a_index) & 1)

The expression is performing a & (bitwise and) operation upon two bytes. One of the bytes is retrieved by the parse-loop and contains various values, the other byte is always 1. The & operation compares the two bytes and sets all bits in the result which are set in both bytes. The result of Asc("A") & 1) would be:

Code: Select all

01000001 ; Asc("A") = 65 = 0x41
00000001 ; 1 = 0x01
--------
00000001
As you can see, the value 1 will always check only the least-significant / rightmost bit. To check the other bits this way they have to be shifted / moved right to position 0, and that's exactly what >> (8 - a_index) does, shifting 7 positions to the right in the first iteration, 6 in the second, and 0 in the last. So the bits are compared in the order 7 to 0. The result of the & operation is either 1 (if the rightmost bit is set) or 0 (if not) and appended to bin.

A bit clearer now?

Edit: As a hint for bin2txt(): x += x =x * 2 = x << 1 (shifting one position to the left eqals multiplying by 2 eqals adding a value to itself).
User avatar
noname
Posts: 516
Joined: 19 Nov 2013, 09:15

Re: Trying to understand txt2bin code from forum

23 Oct 2015, 08:38

Very intruiging !But it is also flawed it seems when the first digit is 1.
Txt:
èèè

Bin:
111010001110100011101000

Txt:
hèè

The (A_LoopField="1") seems to convert the "string" 1 or 0 to "number" 1 or 0 so it can be used to count up.The position of the 1 in the binary will determine how many times it will loop.In pos second from the left it will loop 7 times and gives 128 so all positions with 1 will add up to give the total.

Code: Select all

x:=1
loop 7
x +=x
msgbox %x%
Ithink the function should be corrected like this by initialising x:=0

Code: Select all

bin2txt(bin)
 {
 x:=0
   loop parse, bin
    {
      x += x + (a_loopfield = "1")
      if !mod(a_index, 8)
       {
         txt := txt chr(x)
         x = 0
       }
    }
   return txt
 }
User avatar
dmg
Posts: 287
Joined: 02 Oct 2013, 01:43
Location: "Twelve days north of Hopeless and a few degrees south of Freezing to Death"
Contact:

Re: Trying to understand txt2bin code from forum

24 Oct 2015, 02:33

jNizM wrote:or you let the dll's calc this for you :P
yes, yes I could have a system DLL do the conversion. But as I said, I am doing this for fun. Using a DLL would be a little like strapping a camera to your butler and tossing him out of a plane, then watching the video. Not as much fun. ;)
just me wrote:As a start, the parse-loop will only work properly for strings containing only characters which are represented by exactly one byte.
Yes, using only 8 bits limits usable characters to the first 255 in the ascii/unicode table, but that covers most English characters.
just me wrote:The expression is performing a & (bitwise and) operation upon two bytes. One of the bytes is retrieved by the parse-loop and contains various values, the other byte is always 1. The & operation compares the two bytes and sets all bits in the result which are set in both bytes. The result of Asc("A") & 1) would be:

Code: [Select all] [Download] GeSHi © Codebox Plus

01000001 ; Asc("A") = 65 = 0x41
00000001 ; 1 = 0x01
--------
00000001

As you can see, the value 1 will always check only the least-significant / rightmost bit. To check the other bits this way they have to be shifted / moved right to position 0, and that's exactly what >> (8 - a_index) does, shifting 7 positions to the right in the first iteration, 6 in the second, and 0 in the last. So the bits are compared in the order 7 to 0. The result of the & operation is either 1 (if the rightmost bit is set) or 0 (if not) and appended to bin.
Yes, I think I start to get it. That bit of code is taking the decimal number for a character, and using >> and & to generate that number's binary code by appending 1s and 0s one at a time to the bin var. The math still confuses me but at least there is hope.
just me wrote:A bit clearer now?
Yes, and nice pun. :bravo:
just me wrote:Edit: As a hint for bin2txt(): x += x =x * 2 = x << 1 (shifting one position to the left eqals multiplying by 2 eqals adding a value to itself).
Yeah, I can see the x += x but it is the (a_loopfield = "1")part that I don't understand. noname says it is converting the literal 1 and 0 characters in the input string back into integers, but how is it doing that? I have often appended an empty string to force treating numbers as strings, but I have no idea why this syntax would do the opposite.
noname wrote:The (A_LoopField="1") seems to convert the "string" 1 or 0 to "number" 1 or 0 so it can be used to count up.
OK, but how is it doing that? I know appending non integers or an empty string to an integer forces a script to treat the integer as a string, but I don't see anything in the docs about doing the opposite. I just have no reference point for the syntax of that bit of code.
noname wrote:The position of the 1 in the binary will determine how many times it will loop.In pos second from the left it will loop 7 times and gives 128 so all positions with 1 will add up to give the total.
... I don't understand that at all. :?
noname wrote:Ithink the function should be corrected like this by initialising x:=0
Thank you! I have made the change to my code. I am looking at this and I can't see what difference that makes to how this works. Somehow having x start as 0 instead of blank changes the math, but I can't see how just from looking at it. Again, math is not a skill I have.

Thank you all for responding. I will keep looking at what you posted and trying to figure it out. if anyone wants to add to this or clarify some points please bring it on! :salute:
"My dear Mr Gyrth, I am never more serious than when I am joking."
~Albert Campion
------------------------------------------------------------------------
Website | Demo scripts | Blog | External contact
just me
Posts: 9532
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Trying to understand txt2bin code from forum

24 Oct 2015, 04:27

(a_loopfield = "1") is an expression which will resolve to either 1 (True) or 0 (False) depending of the current value in A_LoopField, which is also either 1 or 0 in this case (BinToTxt()). So 1 or 0 will be added to x.
User avatar
noname
Posts: 516
Joined: 19 Nov 2013, 09:15

Re: Trying to understand txt2bin code from forum

24 Oct 2015, 04:37

Code: Select all

; why initialising x:=0 (x starts empty not 0)

x +=x +1
msgbox Did you gamble it to be 1 ? It is %x%

Just me explained the positional value of "1" in the 8bit binary string so here is a breakdown what happens during the loop.

Code: Select all

x:=0

bin=10000001  ;this calculates the decimal value of the byte

Loop, parse,bin
x +=x +(A_LoopField="1")

msgbox after 8 iterations value is %x%

x:=0

;taking bin apart and calculating the "1" position values
bin=10000000

Loop, parse,bin
{
x +=x +(A_LoopField="1")
msgbox iteration = %A_Index% result %x%
}

msgbox after 8 iterations value is 128

x:=0

bin=00000001

Loop, parse,bin
{
x +=x +(A_LoopField="1")
msgbox iteration = %A_Index% result %x%
}

msgbox after 8 iterations value is 1

The total sum is 129
User avatar
dmg
Posts: 287
Joined: 02 Oct 2013, 01:43
Location: "Twelve days north of Hopeless and a few degrees south of Freezing to Death"
Contact:

Re: Trying to understand txt2bin code from forum

24 Oct 2015, 18:40

just me wrote:(a_loopfield = "1") is an expression which will resolve to either 1 (True) or 0 (False) depending of the current value in A_LoopField, which is also either 1 or 0 in this case (BinToTxt()). So 1 or 0 will be added to x
OK. That it is a comparison and not an assignment makes that syntax a little more reasonable, but still doesn't make sense in context. I have never seen where a comparison can be used outside of something that compares, ie a If or ternary. So I took it out completely and the code still works:

Code: Select all

bin2txt(bin)
 {
   x:=0
   loop parse, bin
    {
      x += x + a_loopfield
      if !mod(a_index, 8)
       {
         txt := txt chr(x)
         x = 0
       }
    }
   return txt
 }
Does that mean (a_loopfield = "1") wasn't actually doing anything for the script?
noname wrote:

Code: Select all

x +=x +1
msgbox Did you gamble it to be 1 ? It is %x%
So this is a time when the script wasn't seeing blank as equal to 0, and it was basically failing to do anything on the first loop iteration. That makes sense, in an abstract way. Thank you.
noname wrote:breakdown what happens during the loop.
That does help some, but the math is still over my head for the moment. Thank you though. :)
"My dear Mr Gyrth, I am never more serious than when I am joking."
~Albert Campion
------------------------------------------------------------------------
Website | Demo scripts | Blog | External contact
just me
Posts: 9532
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Trying to understand txt2bin code from forum

25 Oct 2015, 02:42

dmg wrote:Does that mean (a_loopfield = "1") wasn't actually doing anything for the script?
I'd say it actually does something but isn't needed in this case. The expression resolves to 1, if A_LoopField is "1", and 0, if A_LoopField is "0". Since AHK is treating pure numerical string as numbers you can safely use A_LoopField directly. BTW: Both methods don't check the string for other 'characters' than "0" or "1", so both methods will yield wrong results, then. + (a_loopfield = "1") converts invalid characters to 0 whereas + A_LoopField tries to add the invalid value.
dmg wrote:That does help some, but the math is still over my head for the moment.
In txt2bin() A_LoopField (hopefully) contains a byte value. So you have to Loop 8 times for each byte to get the bits. In bin2txt() A_LoopField represents a single bit, so you have to collect 8 bits to get a byte value. That's what if !mod(a_index, 8) is for. The condition is true whenever mod(a_index, 8) returns 0 (false) and this will happen each time A_Index is a multiple of 8. If so, the character represented by the byte value is appended to the result and the byte value x is set to 0.
You can replace x += x + a_loopfield by x := (x << 1) + A_LoopField to make the functions look more similar:

Code: Select all

Bin := "01000001" ; 0x41 = "A"
; Initialize X
X := 0                           ;  '       0'
; 1st iteration
B := Substr(Bin, 1, 1)
X := (X << 1) + B                ;  '      00'
; 2nd iteration
B := Substr(Bin, 2, 1)
X := (X << 1) + B                ;  '     001'
; 3rd iteration
B := Substr(Bin, 3, 1)
X := (X << 1) + B                ;  '    0010'
; 4th iteration
B := Substr(Bin, 4, 1)
X := (X << 1) + B                ;  '   00100'
; 5th iteration
B := Substr(Bin, 5, 1)
X := (X << 1) + B                ;  '  001000'
; 6th iteration
B := Substr(Bin, 6, 1)
X := (X << 1) + B                ;  ' 0010000'
; 7th iteration
B := Substr(Bin, 7, 1)
X := (X << 1) + B                ;  '00100000'
; 8th iteration
B := Substr(Bin, 8, 1)
X := (X << 1) + B                ; 0'01000001'
MsgBox, % "Bin '" . Bin . "'' = " . "Chr '" . Chr(X) . "'"
User avatar
noname
Posts: 516
Joined: 19 Nov 2013, 09:15

Re: Trying to understand txt2bin code from forum

25 Oct 2015, 10:14

Thank you a thousand times dmg for verifying if turning a string into a number when using parsing loop was needed !I would have made some terrible code from now on thinking this.

Maybe the old version of ahk had a need to convert the string ? Where did you find the original code?

Greetings
User avatar
dmg
Posts: 287
Joined: 02 Oct 2013, 01:43
Location: "Twelve days north of Hopeless and a few degrees south of Freezing to Death"
Contact:

Re: Trying to understand txt2bin code from forum

25 Oct 2015, 16:58

just me wrote:I'd say it actually does something but isn't needed in this case.
You are certainly right that it does something. I confirmed with:

Code: Select all

x := 2
msgbox, % (x = 1)
I have never encountered a comparison used outside of an If or ternary, or similar. I had no idea it would work this way.
just me wrote: BTW: Both methods don't check the string for other 'characters' than "0" or "1", so both methods will yield wrong results, then.
Yes, these functions have no error checking as yet, but for my purposes they don't need any.
just me wrote: so you have to collect 8 bits to get a byte value. That's what if !mod(a_index, 8) is for.
That part of the code I actually understand. Using mod() to create a sort of rotating number 'loop' is something I have used before.
noname wrote:Thank you a thousand times dmg for verifying if turning a string into a number when using parsing loop was needed !I would have made some terrible code from now on thinking this...Where did you find the original code?
Glad to be of service. :D

I found the original code here: autohotkey.com/board/topic/7835-ascii-binary-converter/#entry48740

I think I understand all this well enough in theory to recreate these functions using different syntax. Thank you all for your patient help. When/if I make my own version I will post it back here. :morebeard:
"My dear Mr Gyrth, I am never more serious than when I am joking."
~Albert Campion
------------------------------------------------------------------------
Website | Demo scripts | Blog | External contact
User avatar
dmg
Posts: 287
Joined: 02 Oct 2013, 01:43
Location: "Twelve days north of Hopeless and a few degrees south of Freezing to Death"
Contact:

Re: Trying to understand txt2bin code from forum

27 Oct 2015, 02:37

They are longer, less efficient and unnecessarily use entirely different methodology, but they work!:

Code: Select all

text := "Beware the Jabberwock, my son! The jaws that bite, the claws that catch!"
bin := txt2bin(text)
msgbox % "Txt:`n" text "`n`nBin:`n" bin "`n`nTxt:`n" bin2txt(bin)


txt2bin(txt)
 {
   loop parse, txt
    {
      chr := asc(a_loopfield)
      place := 128
      loop 8
       {
         if(chr >= place)
          {
            chr -= place
            bits .= 1
          }
         else
          {
            bits .= 0
          }
         place /= 2
       }
      bin .= bits
      bits := ""
    }
   return bin
 }

bin2txt(bin)
 {
   count := bits := 0
   place := 128
   loop parse, bin
    {
      if(a_loopfield)
       {
         bits += place
       }
      place /= 2
      count ++
      if(count = 8)
       {
         text .= chr(bits)
         count := 0
         bits := 0
         place := 128
       }
    }
   return text
 }
"My dear Mr Gyrth, I am never more serious than when I am joking."
~Albert Campion
------------------------------------------------------------------------
Website | Demo scripts | Blog | External contact
User avatar
noname
Posts: 516
Joined: 19 Nov 2013, 09:15

Re: Trying to understand txt2bin code from forum

27 Oct 2015, 12:32

but they work!
That is the most important thing !
Image

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: Google [Bot], Rohwedder and 203 guests