VFP AT() Function Equivalent and #translate

394 views
Skip to first unread message

Jeff Stone

unread,
Oct 21, 2015, 10:20:15 AM10/21/15
to Harbour Users
As part of our on-going effort to convert VFP projects to Harbour, we periodically encounter differences in function behavior between VFP and Harbour.  The AT() function when called with more than 2 arguments is one of these instances.  Non-strict Harbour allows 3rd and 4th AT() arguments which are starting and ending string position, respectively. VFP allows a 3rd AT() argument which is number of occurrences. Below is working Harbour code to get the equivalent 3 argument VFP AT() functionality:

FUNCTION VFP_AT_for_HBR(cSub, cStr, nOccurrence )
   LOCAL nCount := 0, nPos := 0, nPos_Prev := 0
   IF HB_ISSTRING( cSub ) .AND. HB_ISSTRING( cStr )
      DO WHILE ( nPos := hb_At( cSub, cStr, nPos + 1 ) ) != 0 .and. nCount < nOccurrence
         ++nCount
         nPos_Prev = nPos
      ENDDO
   ENDIF
IF nCount < nOccurrence
 RETURN 0
ENDIF
RETURN nPos_Prev     

The above function is a modification of Viktor or Przemyslaw's Occurs() function in HBFOXPRO contrib.  Feel free to add this function to that code, if it is deemed worthy.  Ideally, this function should be accompanied by a #translate directive where a 3 argument AT() call would be translated to a VFP_AT_for_HBR() call.  My attempts at creating a #translate directive that only applies to instances of AT() being called with 3 arguments failed.  Sorry.

Anyway, I hope this is helpful to other VFP converts.

Regards,

Jeff

luis vasquez

unread,
Oct 21, 2015, 10:28:04 AM10/21/15
to harbou...@googlegroups.com
Hi Jeff,
you have a harbour function NumAt(), read more in http://vivaclipper.wordpress.com/category/hmg/

NUMAT()

NUMAT()

Number of occurrences of a sequence in a string

Syntax

       NUMAT( <cStringToMatch>, <cString>, [<nIgnore>] ) --> nCount
i hope help you
best regards,
Luis Vasquez

--
--
You received this message because you are subscribed to the Google
Groups "Harbour Users" group.
Unsubscribe: harbour-user...@googlegroups.com
Web: http://groups.google.com/group/harbour-users

---
You received this message because you are subscribed to the Google Groups "Harbour Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to harbour-user...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--
Saludos cordiales,
Luis Vasquez.

Jeff Stone

unread,
Oct 21, 2015, 10:37:19 AM10/21/15
to Harbour Users
I appreciate the information, Luis.  However, the functions are different in that our goal was to find the position of the nth occurrence of the substring while NUMAT() returns the number of occurrences of the substring.

Regards,

Jeff


elch

unread,
Oct 21, 2015, 11:02:56 AM10/21/15
to Harbour Users

Hi Jeff,


suggested NumAt() is originated from Cl*pperTools, aka in the Harbour hbct contrib.


And there is a AtNum() along with other very useful functions.

Check here for doc:

http://www.x-hacker.org/ng/tools1-3/index.html

aka 'string manipulation':

http://www.x-hacker.org/ng/tools1-3/ng3b7f6.html

and there AtNum():

http://www.x-hacker.org/ng/tools1-3/ng40378.html


---

and just add:

hbct.hbc


to your hbmk2 command/ .hbp file to link that contrib


best regards

Rolf

Jeff Stone

unread,
Oct 21, 2015, 11:16:12 AM10/21/15
to Harbour Users
Hi Rolf,

Very helpful links.  Looks like we recreated the wheel.  Since NumAt() still functions differently from AT() and since we are trying to modify our code in such as way as to enable it to compile for both Harbour and VFP, do you know if there a way to use the #translate/#command directive to convert AT() references with 3 arguments to NumAt()?

In other words,
  AT("bc", "abcdef abcdef")
would be left alone but
  AT("bc", "abcdef abcdef", 2)
would translate to
  ATNUM("bc", "abcdef abcdef", 2)

Thanks,

Jeff

Przemyslaw Czerpak

unread,
Oct 21, 2015, 11:20:53 AM10/21/15
to harbou...@googlegroups.com
Hi,

In this code you are making one unnecessary string scan.
You should also check what exactly VFP returns for code like:

FOR i := -1 to 6
? i, at( "ababab", "abababababab", i )
NEXT

If you will send here VFP results from above code, then
I'll add fox_AT() to hbfox library.

best regards,
Przemek

Jeff Stone

unread,
Oct 21, 2015, 11:27:49 AM10/21/15
to Harbour Users
Hi Przemek,

VFP will return error messages at runtime when i is less than 1. If the FOR statement ranges from 1 to 6, then the results are:
  1         1
  2         3
  3         5
  4         7
  5         0
  6         0

Regards,

Jeff


Jeff Stone

unread,
Oct 21, 2015, 11:41:18 AM10/21/15
to Harbour Users
If a #translate directive cannot be constructed just for AT() calls with 3 arguments, then I suppose the function could be changed to:

FUNCTION VFP_AT_for_HBR(cSub, cStr, nOccurrence )
   LOCAL nCount := 0, nPos := 0, nPos_Prev := 0
   IF PCOUNT() < 3
    nOccurrence = 1
   ELSE
    IF nOccurrence < 1
      return 0
    ENDIF
   ENDIF
   IF HB_ISSTRING( cSub ) .AND. HB_ISSTRING( cStr )
      DO WHILE ( nPos := hb_At( cSub, cStr, nPos + 1 ) ) != 0 .and. nCount < nOccurrence
         ++nCount
         nPos_Prev = nPos
      ENDDO
   ENDIF
   IF nCount < nOccurrence
    RETURN 0
   ENDIF
RETURN nPos_Prev

then a #translate directive can apply to all instances of AT()
  #translate AT(<cstring,...>) => VFP_AT_for_HBR(<cstring>)


elch

unread,
Oct 21, 2015, 11:54:31 AM10/21/15
to Harbour Users
Hi Jeff,

... to use the #translate/#command directive to convert AT() references with 3 arguments to NumAt()?

perhaps possible, but i have not all these pre-processor rules right at hand.

You may study yourself here a bit:

https://groups.google.com/d/msg/harbour-users/rBcD9Xp-Vhw/Uxemp5pSsEMJ


---

If you don't already know, i like to point you to also this construction i like to use:


#ifdef __HARBOUR__

// Harbour commands to make something

...

#else

// your VFP commands

...

#endif


but let's wait what Przemek has in mind ;-)


best regards

Rolf

Przemyslaw Czerpak

unread,
Oct 21, 2015, 1:22:46 PM10/21/15
to harbou...@googlegroups.com
Hi,

This code still makes one unnecessary call to hb_at().
Just make things as simple as possible:

FUNCTION fox_At( cSub, cStr, nOccurrence )
LOCAL nPos := 0
IF HB_ISSTRING( cSub ) .AND. HB_ISSTRING( cStr )
hb_default( @nOccurrence, 1 )
DO WHILE --nOccurrence >= 0 .AND. ( nPos := hb_At( cSub, cStr, nPos + 1 ) ) != 0
ENDDO
ENDIF
RETURN nPos

and PP rule:
#xtranslate At( <sub>, <str>, <occur> ) => fox_At( <sub>, <str>, <occur> )

I'll commit it in a while.

best regards,
Przemek


On Wed, 21 Oct 2015, Jeff Stone wrote:
Reply all
Reply to author
Forward
0 new messages