Announcement

Collapse
No announcement yet.

Counting special characters in a string

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Counting special characters in a string

    Hi,

    I use PB to inspect incoming mail for spam signatures beyond the 'normal' stuff most anti-spam packages do. It has worked very well. One thing I need to do is count in a string how many characters there are of a certain type.

    Example...here is a typical line from an incoming email that tries to throw off anti spam engines:
    %^^%*^*(()*^%^^**(*)*()()**(***}}){**\:}!{/(-{{}|^%*^*^*^)())(<><<>?<?<>??<>?<><?>>?<?<><<>?<?><?><?>?><<?><><><><>:":":":"><><<|*}})graphics[]}^|%/*!?[{{#*_^*}|{}*<[{>|%}}*{/[}_\)}/^})^*{/{**^*!}^?}*}}}*}]/{*:{}\{){-}}}}*/_{>^}}^#>*{#|))(}^|^|?{^:}_-**\*/{*}[)}})}]){*}*})%?}})})[(}}}!}{*>)%^^\(}|]^*}{{_^>}!)**})*)){{_{*{>^*{{|)?[%\}#^}}){**\:}!{/(-{{}|{}>*(}^*/#{^!{}|)}})[\}\[/\^_}*{>*-{_{*{>^*{{|)?[%\}#^}}){**\:}!{/(-{{}|^&%*^&*^&*&^)())(<><<>?<?<>??<>?:*!{{/[-*/]\*

    This gets repeated for hundreds of lines. I only look at the first 50. What I'd like to have is a function that returns the overall count of a string of characters withing a larger string.
    spamcount=$findcrap("%^*():{}|",$emstr)
    in this case it would probably be over 100. That to me would be indicative of spam. Add one to the spam count and if it exceeded 10, I kill it.

    Does something like this counting function already exist in PB or something similar? Looked but nothing jumped out at me.

    Thanks!

    --Ben

  • #2
    Hi Ben,
    One way to do it... [Added later: Oops, I did not realize I was in PB-DOS section]

    Click image for larger version  Name:	ChrCount.png Views:	1 Size:	14.2 KB ID:	769990

    Code:
    #COMPILE EXE '#Win 9.07#
    #DIM ALL
    #INCLUDE "Win32Api.inc"
    '_____________________________________________________________________________
    
    FUNCTION PBMAIN() AS LONG
     LOCAL pChar   AS BYTE POINTER
     LOCAL index   AS LONG
     LOCAL sBuffer AS STRING
     LOCAL sLog    AS STRING
     DIM CharCount(0 TO 255) AS LONG
    
     sBuffer = "a%^^%*^*(()*^%^^**(*)*()()**(***}}){**\:}!{/(-{{}|^%*^*^*^z"
     pChar   = STRPTR(sBuffer) 'Get a pointer to sBuffer
     FOR index = 1 TO LEN(sBuffer) 'Scan all character
       INCR CharCount(@pChar) 'Increment the number inside the element array coresponding to the ascii value of the character
       INCR pChar             'Point to the next character
     NEXT
    
     FOR index = 0 TO 255 'Build a log for all characters
       IF CharCount(index) THEN 'If it is not zero then add it to the log
         sLog = sLog & "Chr(" & FORMAT$(index, "000") & ") """ & CHR$(index) & """ found " & FORMAT$(CharCount(index)) & " time(s)" & $CRLF
       END IF
     NEXT
    
     MessageBox(%HWND_DESKTOP, (sLog), "CharCount", %MB_OK OR %MB_TOPMOST) 'Show the log
    
    END FUNCTION
    '_____________________________________________________________________________
    '
    Last edited by Pierre Bellisle; 16 Feb 2018, 10:06 AM.

    Comment


    • #3
      SpamCount = TALLY(strMsg, ANY "%^*():{}|")

      Comment


      • #4
        Ben,

        While you can clean out a lot of the garbage by character filtering, one of the trick I have seen with garbage emails is to deliberately mis-spell certain words. The code below will clean up most junk but there are some tricks that are hard to bypass. The function "charfilter" strips the junk, the function "block_monospace$" formats the text so its closer to readable.
        Code:
        ' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
        
            #include "\basic\include\win32api.inc"
        
        ' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
        
        FUNCTION PBmain as LONG
        
            a$ = "{{{{this||string||||has a{{{{pile of trash in it}}}}"
        
            b$ = block_monospace$(charfilter(a$))
        
            StdOut b$
        
            waitkey$
        
        End FUNCTION
        
        ' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
        
        FUNCTION charfilter(txt$) as STRING
        
            #REGISTER NONE
        
            LOCAL ptxt as DWORD
            LOCAL pbuf as DWORD
            LOCAL slen as DWORD
            LOCAL ptbl as DWORD
        
            ptxt = StrPtr(txt$)
            slen = len(txt$)
            buf$ = space$(slen)
            pbuf = StrPtr(buf$)
            ptbl = CodePtr(chtable)
        
            PREFIX "!"
        
            mov ebx, ptbl
            mov edi, pbuf
            mov edx, ptxt
            sub edx, 1
          lbl:
            add edx, 1
            movzx eax, BYTE PTR [edx]
            test eax, eax
            jz bye                              ; exit on ascii 0
            cmp BYTE PTR [ebx+eax], 0           ; test if char is 0 in table
            jne nxt                             ; 
            mov al, 32
          nxt:
            mov [edi], al                       ; write byte to output string
            add edi, 1
            sub slen, 1                         ; decrement the counter
            jnz lbl
        
          bye:
        
            sub edi, pbuf
            mov slen, edi
        
            END PREFIX
        
            FUNCTION = left$(buf$,slen)
            Exit FUNCTION
        
          ' -------------------------------------------------
          ' table has numbers, upper and lower case and space
          ' -------------------------------------------------
          PREFIX "!"
          chtable:
            db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
            db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
            db 1,0,0,0,1,0,0,0,1,1,0,0,0,0,1,0
            db 1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0
            db 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
            db 1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1
            db 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
            db 1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0
            db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
            db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
            db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
            db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
            db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
            db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
            db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
            db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
          END PREFIX
        
        End FUNCTION
        
        ' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
        
        FUNCTION block_monospace$(src$)
        
          ' -----------------------------------------------------------
          ' left and right trims each line in a block of CRLF delimited
          ' text replacing tabs with spaces and setting single spacing.
          ' DO NOT USE this function on text that does not use BOTH CR
          ' and LF pairs (ASCII 13,10) as results are undefined !
          ' -----------------------------------------------------------
            #REGISTER NONE
        
            LOCAL pst as DWORD
            LOCAL sln as DWORD
        
            dst$ = src$                         ' work on copy
        
            pst = StrPtr(dst$)
        
            ! mov esi, pst
            ! sub esi, 1
            ! mov edi, pst
        
          trm:                                  ' trim leading tabs and spaces
            ! add esi, 1
            ! cmp BYTE PTR [esi], 32
            ! je trm
            ! cmp BYTE PTR [esi], 9
            ! je trm
            ! sub esi, 1
            ! or ebx, -1                        ' set EBX non zero so it falls through the 1st TEST
        
          ' =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
        
          pre:
            ! test ebx, ebx                     ' test for zero AFTER its written.
            ! jz pastit
          stlp:
            ! add esi, 1
            ! movzx ebx, BYTE PTR [esi]
            ! cmp ebx, 9
            ! jne nxt1
            ! mov ebx, 32                       ' replace tabs with spaces
          nxt1:
            ! cmp ebx, 32
            ! jne nxt2
            ! cmp BYTE PTR [esi+1], 32          ' test for next space
            ! je pre
            ! cmp BYTE PTR [esi+1], 9           ' test for next tab
            ! je pre
        
          nxt2:
            ! cmp bl, 13
            ! jne writeit
            ! cmp BYTE PTR [esi-1], 32          ' test for previous space
            ! jne writeit
            ! sub edi, 1                        ' RTRIM trailing space
        
          writeit:
            ! mov [edi], bl                     ' write acceptable character
            ! add edi, 1
        
            ! cmp bl, 10                        ' LTRIM following line
            ! je trm
        
          overit:
            ! test ebx, ebx                     ' test for zero AFTER its written.
            ! jnz stlp
        
          ' =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
        
          pastit:
        
            ! sub edi, 1
            ! cmp BYTE PTR [edi-1], 32          ' if last character is a space
            ! jne nxt3
            ! sub edi, 1
          nxt3:
        
            ! sub edi, pst                      ' length in EDI
            ! mov sln, edi
        
            FUNCTION = left$(dst$,sln)
        
        END FUNCTION
        
        ' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
        hutch at movsd dot com
        The MASM Forum

        www.masm32.com

        Comment


        • #5
          Apologies, it just dawned on me that this subforum is for DOS, not 32 bit Windows. If you need to perform this task in 32 bit, the algos work fine.
          hutch at movsd dot com
          The MASM Forum

          www.masm32.com

          Comment


          • #6
            >INCR CharCount(@pChar)
            This is very elegant because using the ascii value as BOTH thing to count AND index to the counter,
            removes any decision-making and represents the straightest line to what you want.

            Comment


            • #7
              Remove the "@" from Dean's suggestion. pChar is an array index not a pointer (did PBDOS even use @ for pointer targets, or only PEEK/POKE?).

              Maybe rename pChar to iChar where "i" is for "index" (not integer).

              ASC function can be used to change each string character to its' numeric value to put in iChar ((ASC in PBDOS ??? ... must be!)

              Now I'll agree with "elegant".

              Cheers,
              Dale

              Comment


              • #8
                Wow. This is the most impressive forum I've participated in. Not only do I get the answer to the questions posed, but even better solutions than I originally thought of to start with.

                Oh...regarding DOS vs WIndows. I posted apparently in the wrong area. This will be running on a WIn server. But I didn't need the fancy Windows UI version of PB.

                Thanks much!!

                --Ben

                Comment


                • #9
                  But I didn't need the fancy Windows UI version of PB.
                  Then you've got PBCC?

                  That would make all above workable.

                  Cheers,
                  Dale

                  Comment


                  • #10
                    In fact, in my code, "INCR pChar" can be avoided giving a little more speed to the array filling.
                    I like the third one...

                    Code:
                    #COMPILE EXE '#Win 9.07#
                    #DIM ALL
                    #INCLUDE "Win32Api.inc"
                    '_____________________________________________________________________________
                    
                    FUNCTION ShowResult(CharCount() AS LONG) AS LONG
                     LOCAL index   AS LONG
                     LOCAL sLog    AS STRING
                    
                     FOR index = 01 TO 255      'Build a log string buffer for all characters
                       IF CharCount(index) THEN 'If it is not zero then add it to the log
                         sLog = sLog & "Chr(" & FORMAT$(index, "000") & ") """ & CHR$(index) & _
                                """ found " & FORMAT$(CharCount(index)) & " time(s)" & $CRLF
                       END IF
                     NEXT
                     MessageBox(%HWND_DESKTOP, (sLog), "CharCount", %MB_OK OR %MB_TOPMOST) 'Show the log
                    
                    END FUNCTION
                    '_____________________________________________________________________________
                    
                    FUNCTION PBMAIN() AS LONG
                     LOCAL pChar   AS BYTE POINTER
                     LOCAL index   AS LONG
                     LOCAL sBuffer AS STRING
                     DIM CharCount(0 TO 255) AS LONG
                    
                     sBuffer = "a%^^%*^*(()*^%^^**(*)*()()**(***}}){**\:}!{/(-{{}|^%*^*^*^zz"
                     sBuffer = "515225333544445"
                    
                     pChar   = STRPTR(sBuffer)     'Get a pointer to sBuffer
                     FOR index = 1 TO LEN(sBuffer) 'Scan all character
                       INCR CharCount(@pChar)      'Increment the number inside the element array coresponding to the ascii value of the character
                       INCR pChar                  'Point to the next string character
                     NEXT
                     ShowResult(CharCount())
                    
                     RESET CharCount()                 'Prepare for another test
                     pChar = STRPTR(sBuffer)           'Get a pointer to sBuffer
                     FOR index = 0 TO LEN(sBuffer) - 1 'Scan all character
                       INCR CharCount(@pChar[index])   'Increment the number inside the element array coresponding to the ascii value of the character
                     NEXT
                     ShowResult(CharCount())
                    
                     RESET CharCount()                             'Prepare for another test
                     pChar = STRPTR(sBuffer)                       'Get a pointer to sBuffer
                     FOR pChar = pChar TO pChar + LEN(sBuffer) - 1 'Scan all character
                       INCR CharCount(@pChar)                      'Increment the number inside the element array coresponding to the ascii value of the character
                     NEXT
                     ShowResult(CharCount())
                    
                    END FUNCTION
                    '_____________________________________________________________________________
                    '

                    Comment


                    • #11
                      Originally posted by Dale Yarker View Post
                      did PBDOS even use @ for pointer targets, or only PEEK/POKE?
                      Yes, it uses @ for pointers

                      Comment


                      • #12
                        T.A.

                        Though it turns out this thread didn't belong in this channel anyway.
                        Dale

                        Comment


                        • #13
                          If you want to count characters in Win32, you create a 256 member array then scan through the data you want to count incrementing the array location for each character, its simple code and genuinely fast. I probably have an algo somewhere to do this but its not hard to write.

                          Found it.

                          Code:
                          ' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
                          
                          FUNCTION char_count(src$,dwArr() as DWORD) as DWORD
                          
                            ' ---------------------------------------------
                            ' count characters in a dynamic string
                            ' src$ The string to count
                            ' dwArr() an empty array to receive the results
                            ' ---------------------------------------------
                          
                              #REGISTER NONE
                          
                              LOCAL parr as DWORD
                              LOCAL psrc as DWORD
                          
                              redim dwArr(255) as DWORD           ' clear array and redim it to the right size
                          
                              psrc = StrPtr(src$)                 ' get the source string address
                              parr = VarPtr(dwArr(0))             ' get the address of the first array member
                          
                              ! mov esi, psrc
                              ! mov edi, parr
                              ! sub esi, 1
                          
                            ' -----------
                            ' unroll by 4
                            ' -----------
                            #align 4
                            lbl0:
                              ! add esi, 1
                              ! movzx eax, BYTE PTR [esi]         ; zero extend each byte into EAX
                              ! add DWORD PTR [edi+eax*4], 1      ; increment the count for that character
                              ! test eax, eax
                              ! jz lbl1
                          
                              ! add esi, 1
                              ! movzx eax, BYTE PTR [esi]
                              ! add DWORD PTR [edi+eax*4], 1
                              ! test eax, eax
                              ! jz lbl1
                          
                              ! add esi, 1
                              ! movzx eax, BYTE PTR [esi]
                              ! add DWORD PTR [edi+eax*4], 1
                              ! test eax, eax
                              ! jz lbl1
                          
                              ! add esi, 1
                              ! movzx eax, BYTE PTR [esi]
                              ! add DWORD PTR [edi+eax*4], 1
                              ! test eax, eax
                              ! jnz lbl0
                          
                            lbl1:
                              ! sub esi, psrc                     ; calculate the length of the source
                              ! mov FUNCTION, esi                 ; return it to the caller
                          
                          End FUNCTION
                          
                          ' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
                          Last edited by Steve Hutchesson; 18 Feb 2018, 09:15 AM. Reason: Added code.
                          hutch at movsd dot com
                          The MASM Forum

                          www.masm32.com

                          Comment


                          • #14
                            Hi Dale not a big deal but re....
                            >Remove the "@" from Dean's suggestion. pChar is an array index not a pointer

                            Actually I was just commenting on Pierre's elegant line in post 2 which seems to work
                            'cos pChar is declared as byte ptr and to index a 255 dim'd array
                            you need the byte it points to in the string, rather than the byte's address in memory so,,,, I think it is @pChar.

                            I only appreciated this because the other day I did the same thing with words and can't use this shortcut which only applies to single characters.

                            Comment


                            • #15
                              Sorry, from that single line I thought you were pointing to addresses 0 to 255, which is startup territory, sure to crash. That you would not do, so I thought @ was a typo.

                              Now that you mention post 2 I see that it actually is a pointer to a character, and value of charater is index of an array member.

                              And, it is still ellegant like you said.
                              Dale

                              Comment


                              • #16
                                No problem

                                Comment


                                • #17
                                  I implemented this nice CharCount into my Dos-Project:
                                  I load Texts into Byte-Arrays, so that I can use the DOS-Interrupts to read and write up to 64 Kb at once.
                                  As Parameters I give the Sub The Pointer to the first Array-Element, the Number of Elements as the length
                                  of the Text and an ByteArray for the ASCII-Counts:

                                  Code:
                                  Sub CharCount (ByVal dwAdresse As DWord, _
                                                 ByVal wAnzahl As Word, _
                                                       wAsciiTabelle() As Word)
                                  
                                    Dim pChar   AS BYTE POINTER
                                    Dim iIndex   AS Integer
                                  
                                    pChar = dwAdresse
                                  
                                      For iIndex = -32768 To Cint(-32768 + wAnzahl - 1)
                                      Incr wAsciiTabelle(@pChar)
                                      Incr pChar
                                    Next iIndex
                                  
                                  End Sub
                                  It works very nice.

                                  Many Thanks!

                                  Comment


                                  • #18
                                    Here is a short example that shows, why I like this way of working with variable Parameters by using Pointers.

                                    My new Sub CharCount can handle both: Strings an ByteArrays.

                                    The usage of Strings seem to be more easy. But in DOS, where RAM is rare in 16-Bit-Realmode, Strings are less helpful by saving RAM: PowerBASIC needs in DOS 2 Bytes for one StringChar. One "Hello World"-String uses 24 Byte of RAM. 32 kCarStrings use 64 kB of RAM.
                                    By Using ByteArrays, I can read 64 kB directly from Disk into a ByteArray. This way, I get 64 kByte of Text to work and PowerBASIC needs for that only 64 kB of RAM...

                                    CharCount can handle both and I do not need to take care of correct Parametertypes:

                                    Code:
                                                                                                           $If 0
                                    Counts the number of each ASCII-Sign within a ByteArray or a String
                                                                                                           $EndIf
                                    
                                    $Dim     All
                                    $Compile exe
                                    $Lib     All Off
                                    $String  1
                                    $Sound   1
                                    $Error   All Off
                                    $Stack   2048
                                    
                                    Declare _
                                    Sub CharCount (ByVal dwAdresse As DWord, _
                                                   ByVal wAnzahl As Word, _
                                                         wAsciiTabelle() As Word)
                                    
                                    Dim sText                   As String
                                    Dim sSuchText               As String
                                    Dim ptbText                 As Byte Ptr
                                    Dim wAsciiTabelle(0 To 255) As Word
                                    
                                    Dim iDummy                  As Integer
                                    
                                    sText = "PowerBASIC 3.5 for DOS is a cool compiler. You can implement your own thoughts an create interessting Programs. I once had the problem, that I wanted to use a Function with any kind of parameter without using Assambler... " + _
                                            "What was my Way to go? I simply used Pointers! :) One Parameter was the 32-Bit-Adress of the Variable, the other was its Length. This way I can work with a string or a Byte-Array to count all ASCII-Characters in a String/Text."
                                    
                                    Dim bText (1 To Len(sText)) As Byte
                                    
                                    ptbText = StrPtr32(sText)
                                    
                                    '- Fill the Byte-Array to show the magic ;)
                                    
                                    For iDummy = LBound(bText) To UBound(bText)
                                      bText(iDummy) = ASCII(sText, iDummy)
                                    Next iDummy
                                    
                                    ? sText
                                    
                                    '- Was everythin correct?
                                    For iDummy = LBound(bText) To UBound(bText)
                                      ?Chr$(bText(iDummy));
                                    Next iDummy
                                    
                                    ?
                                    
                                    sleep
                                    
                                    '- Let CharCount Handle The String:
                                    CharCount ptbText, _
                                              Cwrd(Len(sText)), _
                                              wAsciiTabelle()
                                    
                                    GoSub ShowResult
                                    
                                    '- Let CharCount Handle The ByteArray
                                    ptbText = VarPtr32(bText(1))
                                    ReDim  wAsciiTabelle(0 To 255) As Word
                                    Dim    wAnzahl                 As Word
                                    wAnzahl = Cwrd(UBound(bText) - LBound(bText))
                                    CharCount ptbText, _
                                              wAnzahl, _
                                              wAsciiTabelle()
                                    
                                    GoSub ShowResult
                                    End
                                    
                                    ShowResult:
                                      '- Show a table of used ASCII-Chars:
                                      ?
                                      For iDummy = LBound(wAsciiTabelle) To UBound(wAsciiTabelle)
                                        If wAsciiTabelle(iDummy) > 0 Then
                                          ? Chr$(iDummy);Using$(": ##,###",wAsciiTabelle(iDummy)),
                                        End If
                                      Next iDummy
                                      ?
                                      '- Show all used ASCII-Chars:
                                      For iDummy = LBound(wAsciiTabelle) To UBound(wAsciiTabelle)
                                        If wAsciiTabelle(iDummy) > 0 Then
                                          ? Chr$(iDummy);
                                        End If
                                      Next iDummy
                                    Return
                                    
                                    Sub CharCount (ByVal dwAdresse As DWord, _
                                                   ByVal wAnzahl As Word, _
                                                         wAsciiTabelle() As Word)
                                                                                                           $If 0
                                      CharCount counts how often each ASCII-Char is used in a String or a
                                      ByteArray with up to 64 kB of Text in it.
                                      The Result is stored in the WordArray wAsciiTabelle().
                                      Old Way: For i = 0 To 255 : x(i) = Tally(sText, Chr$(i)) : next i
                                                                                                           $EndIf
                                      If wAnzahl = 0 Then Exit Sub
                                    
                                      Dim pChar   AS BYTE POINTER
                                      Dim iIndex   AS Integer
                                    
                                      pChar = dwAdresse
                                    
                                        For iIndex = -32768 To Cint(-32768 + wAnzahl - 1)
                                        Incr wAsciiTabelle(@pChar)
                                        Incr pChar
                                      Next iIndex
                                    
                                    End Sub
                                    Output:
                                    Code:
                                    PowerBASIC 3.5 for DOS is a cool compiler. You can implement your own thoughts a
                                    n create interessting Programs. I once had the problem, that I wanted to use a F
                                    unction with any kind of parameter without using Assambler... What was my Way to
                                     go? I simply used Pointers! :) One Parameter was the 32-Bit-Adress of the Varia
                                    ble, the other was its Length. This way I can work with a string or a Byte-Array
                                     to count all ASCII-Characters in a String/Text.
                                    PowerBASIC 3.5 for DOS is a cool compiler. You can implement your own thoughts a
                                    n create interessting Programs. I once had the problem, that I wanted to use a F
                                    unction with any kind of parameter without using Assambler... What was my Way to
                                     go? I simply used Pointers! :) One Parameter was the 32-Bit-Adress of the Varia
                                    ble, the other was its Length. This way I can work with a string or a Byte-Array
                                     to count all ASCII-Characters in a String/Text.
                                    
                                     :     79     !:      1     ):      1     ,:      2     -:      4
                                    .:      8     /:      1     2:      1     3:      2     5:      1
                                    ::      1     ?:      1     A:      5     B:      3     C:      3
                                    D:      1     F:      1     I:      7     L:      1     O:      2
                                    P:      4     S:      4     T:      2     V:      1     W:      2
                                    Y:      1     a:     31     b:      3     c:      9     d:      5
                                    e:     31     f:      3     g:      8     h:     16     i:     20
                                    k:      2     l:      9     m:     10     n:     21     o:     25
                                    p:      5     r:     26     s:     21     t:     35     u:      9
                                    w:     11     x:      1     y:      8
                                     !),-./235:?ABCDFILOPSTVWYabcdefghiklmnoprstuwxy
                                     :     79     !:      1     ):      1     ,:      2     -:      4
                                    .:      7     /:      1     2:      1     3:      2     5:      1
                                    ::      1     ?:      1     A:      5     B:      3     C:      3
                                    D:      1     F:      1     I:      7     L:      1     O:      2
                                    P:      4     S:      4     T:      2     V:      1     W:      2
                                    Y:      1     a:     31     b:      3     c:      9     d:      5
                                    e:     31     f:      3     g:      8     h:     16     i:     20
                                    k:      2     l:      9     m:     10     n:     21     o:     25
                                    p:      5     r:     26     s:     21     t:     35     u:      9
                                    w:     11     x:      1     y:      8
                                     !),-./235:?ABCDFILOPSTVWYabcdefghiklmnoprstuwxy

                                    Comment


                                    • #19
                                      Corrected and a bit optimized Version:
                                      Code:
                                                                                                             $If 0
                                      Counts the number of each ASCII-Sign within a ByteArray or a String
                                                                                                             $EndIf
                                      
                                      $Dim     All
                                      $Compile exe
                                      $Lib     All Off
                                      $String  1
                                      $Sound   1
                                      $Error   All Off
                                      $Stack   2048
                                      
                                      Declare _
                                      Sub CharCount (ByVal dwAdresse As DWord, _
                                                     ByVal wAnzahl As Word, _
                                                           wAsciiTabelle() As Word)
                                      
                                      Dim sText                     As String
                                      Dim ptbText                   As Byte Ptr
                                      Dim wAsciiTabelle(0 To 255) As Word
                                      
                                      Dim iDummy                  As Integer
                                      
                                      sText = "PowerBASIC 3.5 for DOS is a cool compiler. You can implement your own thoughts an create interessting Programs. I once had the problem, that I wanted to use a Function with any kind of parameter without using Assambler... " + _
                                              "What was my Way to go? I simply used Pointers! :) One Parameter was the 32-Bit-Adress of the Variable, the other was its Length. This way I can work with a string or a Byte-Array to count all ASCII-Characters in a String/Text."
                                      
                                      Dim bText (-32768 To -32769 + Len(sText)) As Byte
                                      
                                      ptbText = StrPtr32(sText)
                                      
                                      '- Fill the Byte-Array to show the magic ;)
                                      For iDummy = LBound(bText) To UBound(bText)
                                        bText(iDummy) = ASCII(sText, iDummy+32769)
                                      Next iDummy
                                      
                                      '- Let CharCount Handle The String:
                                      CharCount ptbText, _
                                                Cwrd(Len(sText)), _
                                                wAsciiTabelle()
                                      
                                      GoSub ShowResult
                                      
                                      '- Let CharCount Handle The ByteArray
                                      ptbText = VarPtr32(bText(LBound(bText)))
                                      ReDim  wAsciiTabelle(0 To 255) As Word
                                      Dim    wAnzahl                 As Word
                                      wAnzahl = Cwrd(UBound(bText) - LBound(bText)) + 1
                                      
                                      CharCount ptbText, _
                                                wAnzahl, _
                                                wAsciiTabelle()
                                      
                                      GoSub ShowResult
                                      End
                                      
                                      ShowResult:
                                        '- Show a table of used ASCII-Chars:
                                        ?
                                        For iDummy = LBound(wAsciiTabelle) To UBound(wAsciiTabelle)
                                          If wAsciiTabelle(iDummy) > 0 Then
                                            ? Chr$(iDummy);Using$(": ##,###",wAsciiTabelle(iDummy)),
                                          End If
                                        Next iDummy
                                        ?
                                        '- Show all used ASCII-Chars:
                                        For iDummy = LBound(wAsciiTabelle) To UBound(wAsciiTabelle)
                                          If wAsciiTabelle(iDummy) > 0 Then
                                            ? Chr$(iDummy);
                                          End If
                                        Next iDummy
                                      Return
                                      
                                      Sub CharCount (ByVal dwAdresse As DWord, _
                                                     ByVal wAnzahl As Word, _
                                                           wAsciiTabelle() As Word)
                                                                                                             $If 0
                                        CharCount counts how often each ASCII-Char is used in a String or a
                                        ByteArray with up to 64 kB of Text in it.
                                        The Result is stored in the WordArray wAsciiTabelle().
                                        Old Way: For i = 0 To 255 : x(i) = Tally(sText, Chr$(i)) : next i
                                                                                                             $EndIf
                                        If wAnzahl = 0 Then Exit Sub
                                      
                                        Dim pChar   AS BYTE POINTER
                                        Dim iIndex   AS Integer
                                      
                                        pChar = dwAdresse
                                      
                                          For iIndex = -32768 To Cint(-32769 + wAnzahl)
                                          Incr wAsciiTabelle(@pChar)
                                          Incr pChar
                                        Next iIndex
                                      
                                      End Sub

                                      Comment

                                      Working...
                                      X