PlanetSquires Forums

Please login or register.

Login with username, password and session length
Advanced search  

Author Topic: AfxStr.inc idea  (Read 970 times)

Paul Squires

  • Administrator
  • Master Member
  • *****
  • Posts: 8559
  • Windows 10
    • PlanetSquires Software
AfxStr.inc idea
« on: December 30, 2017, 08:43:56 AM »

I haven't written the code but it does seem like it could be trivial. I suggest a function that clips a substring from a string based on two matching characters. Many times I need to extract text that appears between two different types of matching characters (for example, text between an open parenthesis and a close parenthesis).

I could us INSTR to get the first character and then AfxStrExtract to get the string up to the next character but it would be cool if it was all in one function call.

i = INSTR(wszMainStr, "(")
If i Then wszSubString = AfxStrExtract ( i+ 1, wszMainStr, ")" )

Maybe something like OVERLOAD the current AfxStrExtract function so that the first parameter is a start character to search for rather than a start position?

PRIVATE FUNCTION AfxStrExtract OVERLOAD (BYREF wszStartMatchStr AS WSTRING, BYREF wszMainStr AS WSTRING, BYREF wszMatchStr AS WSTRING) AS CWSTR

I need to express my appreciation for all of the AfxStr functions. Since starting to use them in my code it has made FB programming incredibly easy to the point where it rivals and surpasses string handling in PowerBasic. If you guys are not using Jose's WinFBX library than you are missing out on so much.


Logged
Paul Squires
PlanetSquires Software
FireFly Visual Designer, WinFBE Editor

Josť Roca

  • Moderator
  • Master Member
  • *****
  • Posts: 3087
    • Jos
Re: AfxStr.inc idea
« Reply #1 on: December 30, 2017, 10:41:10 AM »

This can be done using regular expressions, e.g.

Code: [Select]
'#CONSOLE ON
#define UNICODE
#INCLUDE ONCE "Afx/CRegExp.inc"
USING Afx

DIM pRegExp AS CRegExp

' // extract the first match
DIM cwsText AS CWSTR = "blah blah (text beween parentheses) blah blah"
DIM cws AS CWSTR = pRegExp.Extract(cwsText, "([^(]*?)(?=\))")
PRINT cws

' // extract the first match after the 11th position
cwsText = "blah (xxx) blah (text beween parentheses) blah blah"
cws = pRegExp.Extract(11, cwsText, "([^(]*?)(?=\))")
PRINT cws

PRINT
PRINT "Press any key..."
SLEEP

In the pattern "([^(]*?)(?=\))" the characters in bold are the starting and ending delimiters. Therefore, to match other delimiters you only need to change them, e.g. "([^{]*?)(?=\})" (extracts text between curly braces).

If you want to include the delimiters in the extracted text, you can use this pattern: "\(.*?\)")
« Last Edit: December 30, 2017, 10:58:50 AM by Jose Roca »
Logged

Josť Roca

  • Moderator
  • Master Member
  • *****
  • Posts: 3087
    • Jos
Re: AfxStr.inc idea
« Reply #2 on: December 30, 2017, 10:46:52 AM »

> I need to express my appreciation for all of the AfxStr functions.

Well, all started with the ansi functions that you posted time ago, so you're the co-author :)

Paul Squires

  • Administrator
  • Master Member
  • *****
  • Posts: 8559
  • Windows 10
    • PlanetSquires Software
Re: AfxStr.inc idea
« Reply #3 on: December 30, 2017, 11:29:40 AM »

> I need to express my appreciation for all of the AfxStr functions.

Well, all started with the ansi functions that you posted time ago, so you're the co-author :)

Lol, my contribution pales in comparison to the work you've done. :) 
Here's to making 2018 a good Freebasic year with lots of tools and productivity.
Logged
Paul Squires
PlanetSquires Software
FireFly Visual Designer, WinFBE Editor

Josť Roca

  • Moderator
  • Master Member
  • *****
  • Posts: 3087
    • Jos
Re: AfxStr.inc idea
« Reply #4 on: December 30, 2017, 03:24:29 PM »

These two overloaded functions seems to work fine, allow an starting position and the size of the delimiters aren't limited to 1 character.

Code: [Select]
' ========================================================================================
' Returns the portion of a string following the occurrence of a specified delimiter up to
' the second delimiter. If one of the delimiters isn't found, it returns an empty string.
' Parameters:
' nStart: The one-based starting position where to start the search
' wszMainStr: The main string
' wszDelim1: The first delimiter
' wszDelim2: The second delimiter
' This function is case-sensitive.
' Example:
' DIM cwsText AS CWSTR = "blah blah (text beween parentheses) blah blah"
' print AfxStrExtract(cwsText, "(", ")")
' ========================================================================================
PRIVATE FUNCTION AfxStrExtract OVERLOAD (BYREF wszMainStr AS WSTRING, BYREF wszDelim1 AS WSTRING, BYREF wszDelim2 AS WSTRING) AS CWSTR
   DIM nPos1 AS LONG = INSTR(wszMainStr, wszDelim1)
   IF nPos1 = 0 THEN RETURN ""
   nPos1 += LEN(wszDelim1)
   DIM nPos2 AS LONG = INSTR(nPos1, wszMainStr, wszDelim2)
   IF nPos2 = 0 THEN RETURN ""
   DIM nLen AS LONG = nPos2 - nPos1
   RETURN MID(wszMainStr, nPos1, nLen)
END FUNCTION
' ========================================================================================
' ========================================================================================
PRIVATE FUNCTION AfxStrExtract OVERLOAD (BYVAL nStart AS LONG = 1, BYREF wszMainStr AS WSTRING, BYREF wszDelim1 AS WSTRING, BYREF wszDelim2 AS WSTRING) AS CWSTR
   DIM nLen AS LONG = LEN(wszMainStr)
   IF (nStart = 0) OR (nStart > nLen) THEN RETURN ""
   IF nStart < 0 THEN nStart = nLen + nStart + 1
   DIM nPos1 AS LONG = INSTR(nStart, wszMainStr, wszDelim1)
   IF nPos1 = 0 THEN RETURN ""
   nPos1 += LEN(wszDelim1)
   DIM nPos2 AS LONG = INSTR(nPos1, wszMainStr, wszDelim2)
   IF nPos2 = 0 THEN RETURN ""
   nLen = nPos2 - nPos1
   RETURN MID(wszMainStr, nPos1, nLen)
END FUNCTION
' ========================================================================================
« Last Edit: December 30, 2017, 06:32:26 PM by Jose Roca »
Logged

Paul Squires

  • Administrator
  • Master Member
  • *****
  • Posts: 8559
  • Windows 10
    • PlanetSquires Software
Re: AfxStr.inc idea
« Reply #5 on: December 30, 2017, 06:19:53 PM »

Thanks Jose! I've been using it over the past hour and it seems to work quite well in my code so far. Awesome!  :)
Logged
Paul Squires
PlanetSquires Software
FireFly Visual Designer, WinFBE Editor

Paul Squires

  • Administrator
  • Master Member
  • *****
  • Posts: 8559
  • Windows 10
    • PlanetSquires Software
Re: AfxStr.inc idea
« Reply #6 on: December 31, 2017, 12:56:26 PM »

Jose, I've updated to use your very latest WinFBX library code from GitHub. I was able to recompile WinFBE with no errors.
You may want to update your Hstory.txt file to reflect the AfxStrextract changes.
Logged
Paul Squires
PlanetSquires Software
FireFly Visual Designer, WinFBE Editor

Josť Roca

  • Moderator
  • Master Member
  • *****
  • Posts: 3087
    • Jos
Re: AfxStr.inc idea
« Reply #7 on: December 31, 2017, 01:29:30 PM »

Done.

Paul Squires

  • Administrator
  • Master Member
  • *****
  • Posts: 8559
  • Windows 10
    • PlanetSquires Software
Re: AfxStr.inc idea
« Reply #8 on: January 06, 2018, 10:02:27 AM »

Hi Jose, as I am coding today I came across another idea that would be a great time saver for certain situations and it is a compliment to the new AfxStrExtract functions. Maybe extend the AfxStrRemove functions to remove portions of string between matching characters.

For example, in my code I have a need to remove the parenthesis enclosing array variables. I can do it using INSTR and MID, etc but a dedicated function would be nice.

st = "DIM myArray(10) AS LONG"

st = AfxStrRemove( st, "(", ")" )

Result: "DIM myArray AS LONG"

What do you think?
Logged
Paul Squires
PlanetSquires Software
FireFly Visual Designer, WinFBE Editor

Josť Roca

  • Moderator
  • Master Member
  • *****
  • Posts: 3087
    • Jos
Re: AfxStr.inc idea
« Reply #9 on: January 06, 2018, 10:47:59 AM »

Done.

Code: [Select]
' ========================================================================================
' Returns a copy of a string with a substring enclosed between the specified delimiters removed.
' Parameters:
' nStart: [Optional]. The one-based starting position where to start the search
' wszMainStr: The main string
' wszDelim1: The first delimiter
' wszDelim2: The second delimiter
' This function is case-sensitive.
' Example:
' DIM cwsText AS CWSTR = "blah blah (text beween parentheses) blah blah"
' print AfxStrRemove(cwsText, "(", ")")   ' Returns "blah blah  blah blah"
' ========================================================================================
PRIVATE FUNCTION AfxStrRemove OVERLOAD (BYREF wszMainStr AS CONST WSTRING, BYREF wszDelim1 AS WSTRING, BYREF wszDelim2 AS WSTRING) AS CWSTR
   DIM nPos1 AS LONG = INSTR(wszMainStr, wszDelim1)
   IF nPos1 = 0 THEN RETURN wszMainStr
   DIM nPos2 AS LONG = INSTR(nPos1 + LEN(wszDelim1), wszMainStr, wszDelim2)
   IF nPos2 = 0 THEN RETURN wszMainStr
   nPos2 += LEN(wszDelim2)
   DIM nLen AS LONG = nPos2 - nPos1
   RETURN MID(wszMainStr, 1, nPos1 - 1) & MID(wszMainStr, nPos2)
END FUNCTION
' ========================================================================================
' ========================================================================================
PRIVATE FUNCTION AfxStrRemove OVERLOAD (BYVAL nStart AS LONG = 1, BYREF wszMainStr AS CONST WSTRING, BYREF wszDelim1 AS WSTRING, BYREF wszDelim2 AS WSTRING) AS CWSTR
   DIM nLen AS LONG = LEN(wszMainStr)
   IF (nStart = 0) OR (nStart > nLen) THEN RETURN ""
   IF nStart < 0 THEN nStart = nLen + nStart + 1
   DIM nPos1 AS LONG = INSTR(nStart, wszMainStr, wszDelim1)
   IF nPos1 = 0 THEN RETURN wszMainStr
   DIM nPos2 AS LONG = INSTR(nPos1, wszMainStr, wszDelim2)
   IF nPos2 = 0 THEN RETURN wszMainStr
   nPos2 += LEN(wszDelim2)
   nLen = nPos2 - nPos1
   RETURN MID(wszMainStr, 1, nPos1 - 1) & MID(wszMainStr, nPos2)
END FUNCTION
' ========================================================================================

The delimiters aren't limited to one character. Therefore, you can use " (" if you want to remove a leading space.
« Last Edit: January 06, 2018, 11:34:17 AM by Jose Roca »
Logged

Paul Squires

  • Administrator
  • Master Member
  • *****
  • Posts: 8559
  • Windows 10
    • PlanetSquires Software
Re: AfxStr.inc idea
« Reply #10 on: January 06, 2018, 11:16:23 AM »

I just tried it in my code and it works as advertised - thanks!

I am wondering about the situation where multiple instances of the pattern are present in the string. Maybe an AfxStrRemoveAll function?

dim as string st = "As Long var1(34), var2(  73 ), var3(any)"
st = AfxStrRemove(st, "(", ")")
? "Results:  "As Long var1, var2(  73 ), var3(any)"

Whereas an AfxStrRemoveAll would yield:

dim as string st = "As Long var1(34), var2(  73 ), var3(any)"
st = AfxStrRemoveAll(st, "(", ")")
? "Results:  "As Long var1, var2, var3"
Logged
Paul Squires
PlanetSquires Software
FireFly Visual Designer, WinFBE Editor

Josť Roca

  • Moderator
  • Master Member
  • *****
  • Posts: 3087
    • Jos
Re: AfxStr.inc idea
« Reply #11 on: January 06, 2018, 11:34:04 AM »

I have added a boolean flag, fRemoveAll. If TRUE, the functions will remove all the occurrences recursively.

Code: [Select]
' ========================================================================================
' Returns a copy of a string with a substring enclosed between the specified delimiters removed.
' Parameters:
' nStart: [Optional]. The one-based starting position where to start the search
' wszMainStr: The main string
' wszDelim1: The first delimiter
' wszDelim2: The second delimiter
' fRemoveAll: TRUE or FALSE. TRUE = Recursively remove all the occurrences.
' This function is case-sensitive.
' Example:
' DIM cwsText AS CWSTR = "blah blah (text beween parentheses) blah blah"
' print AfxStrRemove(cwsText, "(", ")")   ' Returns "blah blah  blah blah"
' ========================================================================================
PRIVATE FUNCTION AfxStrRemove OVERLOAD (BYREF wszMainStr AS CONST WSTRING, BYREF wszDelim1 AS WSTRING, BYREF wszDelim2 AS WSTRING, BYVAL fRemoveAll AS BOOLEAN = FALSE) AS CWSTR
   DIM nPos1 AS LONG = INSTR(wszMainStr, wszDelim1)
   IF nPos1 = 0 THEN RETURN wszMainStr
   DIM nPos2 AS LONG = INSTR(nPos1 + LEN(wszDelim1), wszMainStr, wszDelim2)
   IF nPos2 = 0 THEN RETURN wszMainStr
   nPos2 += LEN(wszDelim2)
   DIM nLen AS LONG = nPos2 - nPos1
   IF fRemoveAll = FALSE THEN RETURN MID(wszMainStr, 1, nPos1 - 1) & MID(wszMainStr, nPos2)
   RETURN AfxStrRemove(MID(wszMainStr, 1, nPos1 - 1) & MID(wszMainStr, nPos2), wszDelim1, wszDelim2, fRemoveAll)
END FUNCTION
' ========================================================================================
' ========================================================================================
PRIVATE FUNCTION AfxStrRemove OVERLOAD (BYVAL nStart AS LONG = 1, BYREF wszMainStr AS CONST WSTRING, BYREF wszDelim1 AS WSTRING, BYREF wszDelim2 AS WSTRING, BYVAL fRemoveAll AS BOOLEAN = FALSE) AS CWSTR
   DIM nLen AS LONG = LEN(wszMainStr)
   IF (nStart = 0) OR (nStart > nLen) THEN RETURN ""
   IF nStart < 0 THEN nStart = nLen + nStart + 1
   DIM nPos1 AS LONG = INSTR(nStart, wszMainStr, wszDelim1)
   IF nPos1 = 0 THEN RETURN wszMainStr
   DIM nPos2 AS LONG = INSTR(nPos1, wszMainStr, wszDelim2)
   IF nPos2 = 0 THEN RETURN wszMainStr
   nPos2 += LEN(wszDelim2)
   nLen = nPos2 - nPos1
   IF fRemoveAll = FALSE THEN RETURN MID(wszMainStr, 1, nPos1 - 1) & MID(wszMainStr, nPos2)
   RETURN AfxStrRemove(nStart, MID(wszMainStr, 1, nPos1 - 1) & MID(wszMainStr, nPos2), wszDelim1, wszDelim2, fRemoveAll)
END FUNCTION
' ========================================================================================

Paul Squires

  • Administrator
  • Master Member
  • *****
  • Posts: 8559
  • Windows 10
    • PlanetSquires Software
Re: AfxStr.inc idea
« Reply #12 on: January 06, 2018, 12:20:39 PM »

Awesome Jose, works perfectly  :)
Logged
Paul Squires
PlanetSquires Software
FireFly Visual Designer, WinFBE Editor