Announcement

Collapse
No announcement yet.

My TALLY problem

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

  • My TALLY problem

    My TALLY problem!
    This one bit me hard today and all stems from my not reading the help file completely
    When a match is found, the scan for the next match begins at the position immediately following the prior match.
    I have used TALLY in many situations similar to the code below and did not realize until today that it will not always return what I had expected.
    My BAD.
    I did ask for a feature request to extend TALLY so when a match is found and the match string length is greater than 1 start the next match at the position of the prior match.

    So in the slim chance there are other " I don't need no stinkin help file" morons, I submit MyTally.
    James
    Code:
    '=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
    'PBCC or PBWIN
    '=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
    #COMPILE EXE
    #DIM ALL
    #IF NOT %DEF(%WINAPI)
        #IF NOT %DEF(%WINDOWS)
            DECLARE FUNCTION GetStdHandle LIB "KERNEL32.DLL" ALIAS "GetStdHandle" (BYVAL nStdHandle AS DWORD) AS DWORD
            DECLARE FUNCTION AllocConsole LIB "KERNEL32.DLL" ALIAS "AllocConsole" () AS LONG
            %STD_OUTPUT_HANDLE = -11&
            %STD_INPUT_HANDLE  = -10&
            DECLARE FUNCTION LoadLibrary LIB "KERNEL32.DLL" ALIAS "LoadLibraryA" (lpLibFileName AS ASCIIZ) AS LONG
            DECLARE FUNCTION GetProcAddress LIB "KERNEL32.DLL" ALIAS "GetProcAddress" (BYVAL hModule AS DWORD, lpProcName AS ASCIIZ) AS LONG
            DECLARE FUNCTION FreeLibrary LIB "KERNEL32.DLL" ALIAS "FreeLibrary" (BYVAL hLibModule AS DWORD) AS LONG
        #ENDIF
    #ENDIF
    '==============================================================================
    FUNCTION PBMAIN () AS LONG
    
        LOCAL S1 AS STRING
        LOCAL i AS LONG
        AllocConsole
        'This has 3 "BJF1" but 2 are consecutive and TALLY does not pick it up
        S1 = ",B17A,B6,B26B,B26B,B21,B24,B26B,B3,B14A,B26A,B23A,B7A,B11A,B5A,B7B,B14A,B25,B20B" + _
             ",B8,B22,B11A,B25,B17A,B12,BJF2,B15,B3B,B20A,BJF1,B20A,B23B,B11B,B13,B26A,B4A,BJF" + _
             "2,B17B,B14B,BJF2,BJF1,BJF1,B17B,B11B,B1B,B10,B24,B20B,B1A,B23A,B18,B5B,B19,B16,B" + _
             "1,B14B,B23B,B3A,"
        i = TALLY(S1,",BJF1,")
        CPRINT "With Tally   -> " +FORMAT$(i)
        i = MyTally(S1,",BJF1,")
        CPRINT "With MyTally -> " + FORMAT$(i)
        CWAITFORENTER
    
    END FUNCTION
    '==============================================================================
    FUNCTION MyTally(sMain AS STRING,sMatch AS STRING) AS LONG
    
        LOCAL j,k,n,MainLen,MatchLen AS LONG
    
        MatchLen = LEN(sMatch)
        MainLen = LEN(sMain)
        IF MatchLen = 0 OR MainLen = 0 THEN
            EXIT FUNCTION
        END IF
        n = 1
        DO
            k = INSTR(n,sMain,sMatch)
            IF k THEN
                INCR j
                n = k+ MatchLen-1
                IF n > MainLen THEN
                    EXIT LOOP
                END IF
            ELSE
                EXIT LOOP
            END IF
        LOOP
        FUNCTION = j
    
    END FUNCTION
    '==============================================================================
    SUB CPRINT (BYVAL s AS STRING, OPT NoReturn AS LONG)
        LOCAL h,n AS LONG
    
        h = GetStdHandle(%STD_OUTPUT_HANDLE)
        n = FREEFILE
    
        OPEN HANDLE h FOR OUTPUT AS n
    
        IF ISMISSING(NoReturn) THEN
            PRINT# n, s
        ELSE
            PRINT# n, s;
        END IF
    
        CLOSE n
    END SUB
    '==============================================================================
    SUB CWAITFORENTER ()
        LOCAL h,n AS LONG, S AS STRING
    
        h = GetStdHandle(%STD_INPUT_HANDLE)
    
        n = FREEFILE
        OPEN HANDLE h FOR INPUT AS n
        LINE INPUT# n, S
        CLOSE n
    END SUB

  • #2
    You'll have the same problem with PARSECOUNT.

    Check my post, #8 at http://www.powerbasic.com/support/pb...ad.php?t=21402

    You might consider this slightly shorter fix:
    Code:
    q = 1
    do
    p = instr(q, MainString$, MatchString$)
    if p = 0 then exit loop
    incr count
    q = p + 1
    loop
    There are no atheists in a fox hole or the morning of a math test.
    If my flag offends you, I'll help you pack.

    Comment


    • #3
      When a match is found, the scan for the next match begins at the position immediately following the prior match
      Ok....

      But that should get 'em all, shouldn't it?

      e.g. If TALLY finds ",BJF1," at position 100, then it should start looking for the next one at pos 101, which should find all of 'em, shouldn't it?

      Or does "prior match" not mean "this match?"

      ???

      MCM
      Michael Mattias
      Tal Systems (retired)
      Port Washington WI USA
      [email protected]
      http://www.talsystems.com

      Comment


      • #4
        Thanks Mel.

        James

        Comment


        • #5
          You're right MM but PB doesn't work that way.

          Consider the following string: "ZZZZ". How many ZZ's are in that string.

          My logic says there are 3. Positions 1-2, 2-3 and 3-4.

          PB on the other hand will find only two at positions 1-2 and 3-4. The pointer increases its position len(MatchString$) where it should be len(MatchString$) - 1.
          There are no atheists in a fox hole or the morning of a math test.
          If my flag offends you, I'll help you pack.

          Comment


          • #6
            Originally posted by Michael Mattias View Post
            Ok....
            But that should get 'em all, shouldn't it?
            e.g. If TALLY finds ",BJF1," at position 100, then it should start looking for the next one at pos 101, which should find all of 'em, shouldn't it?
            Or does "prior match" not mean "this match?"
            ???
            MCM

            What they don't realize is that they are searching for a count of how many times the entire mask is found. James included both a leading comma and a trailing comma in the mask. But then he wanted to use the trailing comma over again as the leading comma in the next data item.

            Folks, that's not how it works.

            The mask ",BJF1," does not appear twice in the string ",BJF1,BJF1,". It only appears one time.

            Best regards,

            Bob Zale
            PowerBASIC Inc.

            Comment


            • #7
              Well Bob, you're not going to change my mind and I'm not going to change yours.

              I think the ?greater good? of this thread is to make programmers aware of the situation with TALLEY and PARSECOUNT so they can take programming steps to return the value(s) they are expecting.
              There are no atheists in a fox hole or the morning of a math test.
              If my flag offends you, I'll help you pack.

              Comment


              • #8
                Well, the fact is that I'm not trying to change anyone's mind. I'm only suggesting they read the documentation and apply that information to the problem. If you want a function that's different than the one we provide, wouldn't it be better to write it yourself? Why insist that ours is wrong? You are a programmer, why not just write a program? <smile>

                Bob Zale
                PowerBASIC Inc.

                Comment


                • #9
                  So "next position" does not mean "plus one", it means "start position plus LENGTH OF SEARCH TOKEN?

                  MCM
                  Michael Mattias
                  Tal Systems (retired)
                  Port Washington WI USA
                  [email protected]
                  http://www.talsystems.com

                  Comment


                  • #10
                    Originally posted by Bob Zale View Post
                    ...wouldn't it be better to write it yourself...
                    I already did.
                    There are no atheists in a fox hole or the morning of a math test.
                    If my flag offends you, I'll help you pack.

                    Comment


                    • #11
                      Originally posted by Bob Zale View Post
                      The mask ",BJF1," does not appear twice in the string ",BJF1,BJF1,". It only appears one time.

                      Best regards,

                      Bob Zale
                      PowerBASIC Inc.
                      As one of the dimmer bulbs in this stadium, someone is going to have to shed some light on this one for me. I see ",BJF1," appearing twice in ",BJF1,BJF1,".

                      Once at ",BJF1, and second at ,BJF1," (excluding quotes of course)

                      Or is that what the confusion is about?

                      ========================================================
                      It seems to me, Golan, that the advance of civilization
                      is nothing but an exercise in the limiting of privacy.
                      Isaac Asimov, Foundation's Edge (1920- 1992)
                      ========================================================
                      It's a pretty day. I hope you enjoy it.

                      Gösta

                      JWAM: (Quit Smoking): http://www.SwedesDock.com/smoking
                      LDN - A Miracle Drug: http://www.SwedesDock.com/LDN/

                      Comment


                      • #12
                        Originally posted by Gösta H. Lovgren-2 View Post
                        As one of the dimmer bulbs in this stadium, someone is going to have to shed some light on this one for me. I see ",BJF1," appearing twice in ",BJF1,BJF1,".

                        Once at ",BJF1, and second at ,BJF1," (excluding quotes of course)

                        Or is that what the confusion is about?

                        It appears twice if you take overlaps into account, once if you don't.

                        If you strip the first ",BJFI," from ",BJF1,BJF1," you are left with "BJF1," and not ",BJF1,".

                        What do you expect from REPLACE ",BJF1," with "*" in ",BJF1,BJF1,"?

                        I would expect "*BJF1," and not "**"

                        Same should apply to TALLY and PARSECOUNT ( and it does).

                        Comment


                        • #13
                          Not to quibble Stuart but "The mask ',BJF1,' does not appear twice in the string ',BJF1,BJF1,'. It only appears one time." was the statement.

                          Not "The mask ',BJF1,' does not appear twice in the string ',BJF1,BJF1,'. It only appears one time if you remove the first one found."

                          =============================================
                          "The covers of this book are too far apart."
                          Ambrose Bierce (1842-1914)
                          =============================================
                          It's a pretty day. I hope you enjoy it.

                          Gösta

                          JWAM: (Quit Smoking): http://www.SwedesDock.com/smoking
                          LDN - A Miracle Drug: http://www.SwedesDock.com/LDN/

                          Comment


                          • #14
                            Originally posted by Michael Mattias View Post
                            Ok....

                            But that should get 'em all, shouldn't it?

                            e.g. If TALLY finds ",BJF1," at position 100, then it should start looking for the next one at pos 101, which should find all of 'em, shouldn't it?

                            Or does "prior match" not mean "this match?"

                            ???

                            MCM
                            The match for the string ",BJF1" is not at position 100, it only starts at position 100. The match is at position 100 - 104. So the next search starts at position 105.

                            Comment


                            • #15
                              Not to quibble Stuart but "The mask ',BJF1,' does not appear twice in the string ',BJF1,BJF1,'. It only appears one time." was the statement.

                              Not "The mask ',BJF1,' does not appear twice in the string ',BJF1,BJF1,'. It only appears one time if you remove the first one found."
                              Gösta
                              If you read from left to right, like the computer is doing, once you have read the first 6 characters, the mask does not appear a second time even if you don't remove the first occurrence since one would be rereading the last(6th) character to get a second occurrence.
                              In "tabletablet", tablet only appears once, as in "tablet"+"ablet".
                              However, if one was playing a word game, they might see a second occurrence because they aren't following normal reading patterns.
                              Rod
                              In some future era, dark matter and dark energy will only be found in Astronomy's Dark Ages.

                              Comment


                              • #16
                                And for a word game you need to search in the reverse order too!
                                "The trouble with quotes on the Internet is that you can never know if they are genuine." - Abraham Lincoln.

                                Comment


                                • #17
                                  The important point to remember here is that the TALLY() function counts only whole string sections found. That's how it's documented and that's how it's implemented. There are probably other intrinsic functions which operate similarly. We implemented it in that fashion because we felt that would be the most common need of our customers.

                                  If you have a need for a different functionality (like overlap of sections allowed), the best thing to do is write a simple function to do what you need, using multiple calls to INSTR(). If you find that idea works well, submit a new feature suggestion with all the details and perhaps even a suggested syntax. You'd be surprised how well that works. You talk...PowerBASIC Listens.

                                  Best regards,

                                  Bob Zale
                                  PowerBASIC Inc.

                                  Comment


                                  • #18
                                    >You talk...PowerBASIC Listens.

                                    "'Next Position' in the help is too vague and should be updated in the next version of the help file, preferably with this very example."

                                    MCM
                                    Michael Mattias
                                    Tal Systems (retired)
                                    Port Washington WI USA
                                    [email protected]
                                    http://www.talsystems.com

                                    Comment


                                    • #19
                                      Originally posted by Rodney Hicks View Post
                                      Gösta
                                      If you read from left to right, like the computer is doing, once you have read the first 6 characters, the mask does not appear a second time even if you don't remove the first occurrence since one would be rereading the last(6th) character to get a second occurrence.
                                      In "tabletablet", tablet only appears once, as in "tablet"+"ablet".
                                      However, if one was playing a word game, they might see a second occurrence because they aren't following normal reading patterns.
                                      Oh Rodney, oh my buddy Rodney, fellow portrait monitor user, Easy Tape collaborator, brother programmer, comrade in arms against the mighty forces of SDK, it pains me, pains me I tell you, to disagree with you. A sad sad day for this old man indeed.

                                      Code:
                                      strt = 1
                                      10
                                      i = instr(strt, "[B],BJF1,BJF1,",",BJF1,")[/B]
                                      if i then
                                        incr match
                                        strt = i + 1
                                        goto 10
                                      end if
                                       
                                      ? "Number of matches" & str$(Match) 'comes out [B][SIZE=3]2[/SIZE][/B] every time

                                      ==================================
                                      "There is one thing certain,
                                      namely,
                                      that we can have nothing certain;
                                      therefore it is not certain
                                      we can have nothing certain."
                                      Samuel Butler (1835-1903)
                                      ==================================
                                      It's a pretty day. I hope you enjoy it.

                                      Gösta

                                      JWAM: (Quit Smoking): http://www.SwedesDock.com/smoking
                                      LDN - A Miracle Drug: http://www.SwedesDock.com/LDN/

                                      Comment


                                      • #20
                                        The problem here is just basically a fencepost error. You're trying to use single delimiters as double delimiters, so of course you're getting unexpected results. If the delimiter needs to appear on BOTH sides of the value, your starting string should look like this:

                                        ",BJF1,,BJF1,"

                                        Note the double comma in the middle. You need a starting and ending delimiter for each item, if that's what you're searching for. The question is, why are you including delimiters in your search string at all? The idea of delimiters is, they're not part of your data, and shouldn't be part of your search.

                                        Use single delimiters between items, rather than as start-and-end markers, and PARSE$ will be your friend.

                                        Comment

                                        Working...
                                        X