# Need help with some text functions

**URL:** <https://clarionhub.com/t/need-help-with-some-text-functions/3919>\
**Category:** questions\
**Tags:** c11\
**Created:** [March 6, 2021, 3:38pm UTC](https://clarionhub.com/t/need-help-with-some-text-functions/3919 "2021-03-06T15:38:33Z")\
**Posts on this page:** 17\
**Page:** 2

<div class="post-metadata">

**Author:** ![vitesse](https://clarionhub.com/user_avatar/clarionhub.com/vitesse/32/837_2.png) [@vitesse](https://clarionhub.com/u/vitesse)\
**Post date:** [March 8, 2021, 12:25pm UTC](https://clarionhub.com/t/need-help-with-some-text-functions/3919/23 "2021-03-08T12:25:25Z")

</div>

> [@CarlBarnes](#):
>
> At a DAB talk answering a question he said the USHORT would be the most efficient LOOP variable if you can live with the 65535 limit. If was off the cuff and I have never tested.

I wonder if that was from the days of a 16 bit compiler as I have always understood LONGs to be fastest in 32 bit. When I get time I will do some testing.

thanks Carl for delving into the generated assembly to see why using numeric comparisons is faster than the string comparisons on the case statements.

---

<div class="post-metadata">

**Author:** ![vitesse](https://clarionhub.com/user_avatar/clarionhub.com/vitesse/32/837_2.png) [@vitesse](https://clarionhub.com/u/vitesse)\
**Post date:** [March 8, 2021, 12:42pm UTC](https://clarionhub.com/t/need-help-with-some-text-functions/3919/24 "2021-03-08T12:42:49Z")

</div>

> [@Bruce](#):
>
> ```auto
> CASE pName[X]
> OF 'A' to 'Z'
> 
> ```
> 
> Technically this line is already wrong. It should read
> 
> ```auto
> CASE Sub(pName,x,1)
> OF 'A' to 'Z'
> 
> ```

yes perhaps “technically”. We will all face challenges if/when forced to use Unicode or I guess any other data format where there is no longer a 1:1 correspondence between byte and character.

And so old habits will need to change if/when that time comes and code will need to be re-visited. I guess it depends if you know the format of your data and if you want to take the inevitable performance hit earlier or later.

On the one hand you have the “don’t waste resources coding now for things that may never happen” school and on the other you have “just remember Y2K”.

Of course some users (depending on the languages they are catering for) may already have this requirement and so will already have adjusted their coding practices whereas for others (perhaps mainly English speaking?) this is yet to become an issue.

anyway at the least it is something to be aware of and bear in mind.

---

<div class="post-metadata">

**Author:** ![vitesse](https://clarionhub.com/user_avatar/clarionhub.com/vitesse/32/837_2.png) [@vitesse](https://clarionhub.com/u/vitesse)\
**Post date:** [March 8, 2021, 12:47pm UTC](https://clarionhub.com/t/need-help-with-some-text-functions/3919/25 "2021-03-08T12:47:01Z")

</div>

> [@DonnEdwards](#):
>
> I’m getting “ **No Matching Prototype available** ” errors with the new procedures. I commented out the second one to help with narrowing down the problem.

Donn you are putting a procedure in the embed that mentions Routines.

See if there is something like

! Start of “Local Procedures”

and if using a local procedure you will also need to put a prototype in a MAP.

I usually put in a MAP just before the procedure’s CODE statement.

But to be honest it is probably easier for a beginner to not have the procedures local - just create separate procedures and if you make them global (there is a check box) then they will be in scope and all should compile without further problems.

---

<div class="post-metadata">

**Author:** ![Bruce](https://clarionhub.com/letter_avatar_proxy/v4/letter/b/ccd318/32.png) [@Bruce](https://clarionhub.com/u/Bruce)\
**Post date:** [March 8, 2021, 1:40pm UTC](https://clarionhub.com/t/need-help-with-some-text-functions/3919/27 "2021-03-08T13:40:15Z")

</div>

> [@vitesse](#):
>
> We will all face challenges if/when forced to use Unicode or I guess any other data format where there is no longer a 1:1 correspondence between byte and character.

The sooner we start _thinking_ in terms of 1 char \<\> 1 byte, and the sooner we start applying that to our code the  
a) easier it will be to refactor old code when the time comes and  
b) less code will need refactoring when the time comes.

---

<div class="post-metadata">

**Author:** ![DonnEdwards](https://clarionhub.com/user_avatar/clarionhub.com/donnedwards/32/1047_2.png) [@DonnEdwards](https://clarionhub.com/u/DonnEdwards)\
**Post date:** [March 8, 2021, 2:13pm UTC](https://clarionhub.com/t/need-help-with-some-text-functions/3919/28 "2021-03-08T14:13:40Z")

</div>

> [@vitesse](#):
>
> Donn you are putting a procedure in the embed that mentions Routines.
> 
> See if there is something like
> 
> ! Start of “Local Procedures”
> 
> and if using a local procedure you will also need to put a prototype in a MAP.
> 
> I usually put in a MAP just before the procedure’s CODE statement.
> 
> But to be honest it is probably easier for a beginner to not have the procedures local - just create separate procedures and if you make them global (there is a check box) then they will be in scope and all should compile without further problems.

Thanks for sorting out my confusion. I am busy experimenting.

In the meantime I have another solution, based on what Bruce said, in the TakeCompleted section of the form

 ![Capture](https://clarionhub-uploads.s3.eu-north-1.amazonaws.com/original/2X/9/92f09a4da4af441d4f342dcb3d363c6169653042.png)

The DO FullNameCalc is working exactly as I wanted, too.

**Everyone who contributed has taught me something, for which I am most grateful. Thank you one and all!**

---

<div class="post-metadata">

**Author:** ![Mike\_Duglas](https://clarionhub.com/user_avatar/clarionhub.com/mike_duglas/32/1061_2.png) [@Mike\_Duglas](https://clarionhub.com/u/Mike_Duglas)\
**Post date:** [March 8, 2021, 4:10pm UTC](https://clarionhub.com/t/need-help-with-some-text-functions/3919/29 "2021-03-08T16:10:04Z")

</div>

I see that the problem is solved, just want to add one more solution with regular expressions (one of the Clarion implementations could be found [here](https://github.com/mikeduglas/ActiveScripting)). Below is SortField calculation as Donn described in starting topic.

```
sSortField STRING(6)
re TJSRegExp

  re.CreateNew('[^a-zA-Z]', 'g') !- remove any char except latin letters
  sSortField[1:3] = UPPER(re.Replace(pLastName, ''))
  sSortField[4:6] = LOWER(re.Replace(pFirstName, ''))
  
  MESSAGE(sSortField)

```

---

<div class="post-metadata">

**Author:** ![CarlBarnes](https://clarionhub.com/user_avatar/clarionhub.com/carlbarnes/32/1859_2.png) [@CarlBarnes](https://clarionhub.com/u/CarlBarnes)\
**Post date:** [March 8, 2021, 4:32pm UTC](https://clarionhub.com/t/need-help-with-some-text-functions/3919/30 "2021-03-08T16:32:59Z")

</div>

> [@DonnEdwards](#):
>
> I know exactly how to do this in _Visual Basic_ , but not in _Clarion_ . An example would help me greatly.

You said you wanted to learn Clarion … Being able to create your own Functions and call them is a common need. I’ll repost the code and the MAP you need to do that …

I’ll keep it simple. My chars have 8 bits, just like .KeepChars() works Bruce. I’ll make them local functions, when that works we can make the APP functions.

#1 - In Embed “_Local Data - Other Declarations_” put the MAP Prototype declarions. In Clarion you must Declare and Define.

```
   MAP
SortName3x3 PROCEDURE(STRING pFirstName, STRING pLastName),STRING
SortPart4Name PROCEDURE(*STRING pName, BOOL pIsLastName=1, BYTE pLenPart=3),STRING
   END

```

#2 - In Embed “_Local Procedures_” define your Procedure. Note here the “Parameters” have the RETURN as a ! comment `()!,STRING` because that only goes in the MAP.

```
SortName3x3 PROCEDURE(STRING pFirstName, STRING pLastName) !,STRING
    CODE
    RETURN SortPart4Name(pLastName, 1,3) & |
           SortPart4Name(pFirstName,0,3) 

SortPart4Name PROCEDURE(*STRING pName, BOOL pIsLastName=1, BYTE pLenPart=3) !,STRING
Part STRING(pLenPart) !<-- Sized as specified
P BYTE
X LONG,AUTO
    CODE
    LOOP X=1 TO SIZE(pName)
        CASE pName[X]
        OF 'a' to 'z' !First as more common                                             
        OROF 'A' to 'Z'
           P += 1
           Part[P]=pName[X]
           IF P=pLenPart THEN BREAK.
        END
    END
    Part=CHOOSE(~pIsLastName,lower(Part),UPPER(Part))
    RETURN Part

```

#3 - In Embed “_Procedure Routines_”

```
NameCalcs ROUTINE
  Cus:FullName=LEFT(CLIP(Cus:FirstName)&' ') & Cus:LastName
  DISPLAY(?Cus:FullName)
  Cus:SortField=SortName3x3(Cus:FirstName,Cus:LastName)
  DISPLAY(?Cus:SortField)    

```

The code you posted earlier had an extra “)” that would cause a compile error.

 ![image](https://clarionhub-uploads.s3.eu-north-1.amazonaws.com/original/2X/4/44df1d96e10d9233f4baf222d62a921cb81ac580.png)

I’ll toss out this code as possibly better for non A-Z alphabets. I don’t deal with international issues so YMMV. Read the docs on IsLower(). Edit: change \*STRING to no \* because PName gets changed.

```
SortPart4Name PROCEDURE(STRING pName, BOOL pIsLastName=1, BYTE pLenPart=3) !,STRING
Part STRING(pLenPart) !<-- Sized as specified
P BYTE
X LONG,AUTO
    CODE
    pName=CHOOSE(~pIsLastName,lower(pName),UPPER(pName))
    LOOP X=1 TO SIZE(pName)
        IF ( pIsLastName AND isUPPER(pName[X])) |
        OR (~pIsLastName AND ISlower(pName[X])) THEN 
           P += 1
           Part[P]=pName[X]
           IF P=pLenPart THEN BREAK.
        END
    END
    RETURN Part

```

---

<div class="post-metadata">

**Author:** ![vitesse](https://clarionhub.com/user_avatar/clarionhub.com/vitesse/32/837_2.png) [@vitesse](https://clarionhub.com/u/vitesse)\
**Post date:** [March 8, 2021, 10:27pm UTC](https://clarionhub.com/t/need-help-with-some-text-functions/3919/31 "2021-03-08T22:27:01Z")

</div>

> [@DonnEdwards](#):
>
> In the meantime I have another solution, based on what Bruce said, in the TakeCompleted section of the form

Hello again Donn

to be honest this is something of a variation on what I gave you early on (just scroll up) when I posted :

```
st stringTheory
sortField stringTheory

(snip)

st.setValue(upper(LastName))
st.keepChars(‘ABCDEFGHIJKLMNOPQRSTUVWXYZ’)
sortField.setvalue(st.slice(1,3))
sortField.setLength(3) ! in case last name < 3 chars

st.setValue(lower(FirstName))
st.keepChars(‘abcdefghijklmnopqrstuvwxyz’)
sortField.append(st.slice(1,3))

mySortField = sortField.getValue()   

```

However there is a bug in what you have now implemented in that it does not cater for the possibility of a last name with fewer than 3 characters. This was the purpose of this line above:

sortField.setLength(3) ! in case last name \< 3 chars

---

<div class="post-metadata">

**Author:** ![vitesse](https://clarionhub.com/user_avatar/clarionhub.com/vitesse/32/837_2.png) [@vitesse](https://clarionhub.com/u/vitesse)\
**Post date:** [March 9, 2021, 2:54am UTC](https://clarionhub.com/t/need-help-with-some-text-functions/3919/32 "2021-03-09T02:54:54Z")

</div>

just another thought Donn as there are always lots of ways to do these things.

where you currently have

cus:SortField = stL.sub(1,3) & stF.sub(1,3)

you could fix the problem of a short Last Name by using string slicing on the LHS as Mike did in his example:

cus:SortField[1 : 3] = stL.sub(1,3)  
cus:SortField[4 : 6] = stF.sub(1,3)

note you could also have used stL.slice(1,3) or even just stL.getvalue()

in fact you could have done it with just one ST object:

```
st stringTheory

(snip)

st.setValue(upper(cus:LastName))
st.keepChars(‘ABCDEFGHIJKLMNOPQRSTUVWXYZ’)
cus:SortField[1 : 3] = st.slice(1,3)

st.setValue(lower(cus:FirstName))
st.keepChars(‘abcdefghijklmnopqrstuvwxyz’)
cus:SortField[4 : 6] = st.slice(1,3)

```

again you could have just used st.getValue() instead of st.slice(1,3) or st.sub(1,3) but I think the intention is probably clearer using slice or sub.

re Carl’s comment about learning Clarion, I agree you will learn more doing it by “long hand” and I recommend you get Carl’s version working for you and make sure you study and understand it as you will definitely learn more.

once you have that knowledge it will also help you understand that string classes like ST can save you a lot of work.

---

<div class="post-metadata">

**Author:** ![DonnEdwards](https://clarionhub.com/user_avatar/clarionhub.com/donnedwards/32/1047_2.png) [@DonnEdwards](https://clarionhub.com/u/DonnEdwards)\
**Post date:** [March 9, 2021, 11:18am UTC](https://clarionhub.com/t/need-help-with-some-text-functions/3919/33 "2021-03-09T11:18:45Z")

</div>

> [@CarlBarnes](#):
>
> You said you wanted to learn Clarion

**You guys have all taught me so much**. I’m really grateful. It has given me the confidence to continue with my project. I will pay it forward at some point.

Thank you to Carl, Geoff, Mike, Bruce, Richard, Douglas, Jeff and Sean. You have each taught me stuff, and encouraged me tremendously, even when I got things wrong.

---

<div class="post-metadata">

**Author:** ![seanh](https://clarionhub.com/letter_avatar_proxy/v4/letter/s/4af34b/32.png) [@seanh](https://clarionhub.com/u/seanh)\
**Post date:** [March 10, 2021, 5:55am UTC](https://clarionhub.com/t/need-help-with-some-text-functions/3919/34 "2021-03-10T05:55:42Z")

</div>

You learn more by fixing a fkuc up than any other time 😆 .. and the stress usually means you remember it for next time 🙃

---

<div class="post-metadata">

**Author:** ![DonnEdwards](https://clarionhub.com/user_avatar/clarionhub.com/donnedwards/32/1047_2.png) [@DonnEdwards](https://clarionhub.com/u/DonnEdwards)\
**Post date:** [March 10, 2021, 7:50am UTC](https://clarionhub.com/t/need-help-with-some-text-functions/3919/35 "2021-03-10T07:50:27Z")

</div>

That is absolutely true, and funny too 🤣 I have made plenty of mistakes and you guys have been gracious enough to help me fix them and learn.

---

<div class="post-metadata">

**Author:** ![vitesse](https://clarionhub.com/user_avatar/clarionhub.com/vitesse/32/837_2.png) [@vitesse](https://clarionhub.com/u/vitesse)\
**Post date:** [October 18, 2024, 2:28am UTC](https://clarionhub.com/t/need-help-with-some-text-functions/3919/36 "2024-10-18T02:28:28Z")

</div>

> [@CarlBarnes](#):
>
> ```auto
> NameCalcs ROUTINE
> FullName=LEFT(CLIP(FirstName)&' ') & LastName !Left() incase First Name Blank
> 
> ```

funny I just came across this earlier conversation from three and a half years ago and noticed the above.

at the time I had endorsed this without qualification:

> [@vitesse](#):
>
> as Carl said, for fullname use
> 
> FullName = left(clip(FirstName)&’ ') & LastName

but re-reading it now the closing bracket for the left seems to be misplaced. I think this is what was intended:

```clarion
FullName=LEFT(CLIP(FirstName)&' ' & LastName) !Left() incase First Name Blank

```

the reason for this is that doing a left on a blank string does not alter it so if FirstName was blank, the way it was you would still have a space at the start.

@DonnEdwards you might want to check your code and alter it if you used that.

And while I am here, from the current ST version 3.70 on, where I said:

> st.keepChars(‘ABCDEFGHIJKLMNOPQRSTUVWXYZ’)

you can now simply say

> st.keepCharRanges(‘A-Z’)

and ditto for

> st.keepChars(‘abcdefghijklmnopqrstuvwxyz’)

you can now say

> st.keepCharRanges(‘a-z’)

---

<div class="post-metadata">

**Author:** ![RchdR](https://clarionhub.com/letter_avatar_proxy/v4/letter/r/d78d45/32.png) [@RchdR](https://clarionhub.com/u/RchdR)\
**Post date:** [October 18, 2024, 3:36am UTC](https://clarionhub.com/t/need-help-with-some-text-functions/3919/37 "2024-10-18T03:36:12Z")

</div>

> [@vitesse](#):
>
> st.keepCharRanges(‘a-z’)

Looks like case insensitive RegEx (StrPos/match) talk.

@DonnEdwards doesnt mention if using ABC, but if so, that code can go into the global embeds.

Field level validation  
Table/Filename:?  
Field: Fullname  
Create Source embed with Priority 4000  
Add the code  
FullName = left(clip(FirstName)&’ ') & LastName

Then everytime the record is updated, the code runs. This is handy when you have a one or more procedures (forms/processes/source) updating the records because the code to update and maintain Fullname is stored once globally and performed whenever any procedure updates that file, eliminating any risks of cut n paste code errors creeping in.

---

<div class="post-metadata">

**Author:** ![vitesse](https://clarionhub.com/user_avatar/clarionhub.com/vitesse/32/837_2.png) [@vitesse](https://clarionhub.com/u/vitesse)\
**Post date:** [October 18, 2024, 4:50am UTC](https://clarionhub.com/t/need-help-with-some-text-functions/3919/38 "2024-10-18T04:50:26Z")

</div>

> [@RchdR](#):
>
> > [@vitesse](#):
> >
> > st.keepCharRanges(‘a-z’)
> 
> Looks like case insensitive RegEx (StrPos/match) talk.

yes a little, but character ranges so it is case sensitive. But you could say

> st.keepCharRanges(‘a-zA-Z’)

which will then keep _both_ lower and upper case letters (and get rid of everything else)

> [@RchdR](#):
>
> Add the code  
> FullName = left(clip(FirstName)&’ ') & LastName

hey! 😀 I’m sure you really meant:

> FullName = left(clip(FirstName)&’ ’ & LastName)

> [@RchdR](#):
>
> Then everytime the record is updated, the code runs.

that sounds a bit like dictionary (client side) triggers

cheers for now

---

<div class="post-metadata">

**Author:** ![RchdR](https://clarionhub.com/letter_avatar_proxy/v4/letter/r/d78d45/32.png) [@RchdR](https://clarionhub.com/u/RchdR)\
**Post date:** [October 18, 2024, 9:41am UTC](https://clarionhub.com/t/need-help-with-some-text-functions/3919/39 "2024-10-18T09:41:39Z")

</div>

So ST is using regexes then. I saw an entry in the docs on regex but no methods other than this housekeeping one and possibly a few others? Are any of the methods that use regex labelled?

Yeah the field level validation is like a dct trigger but working at the field level. Its where the dct field validation code appears like the dct must be in file and the others seen on that tab in the dct.

---

<div class="post-metadata">

**Author:** ![vitesse](https://clarionhub.com/user_avatar/clarionhub.com/vitesse/32/837_2.png) [@vitesse](https://clarionhub.com/u/vitesse)\
**Post date:** [October 18, 2024, 11:11am UTC](https://clarionhub.com/t/need-help-with-some-text-functions/3919/40 "2024-10-18T11:11:42Z")

</div>

> [@RchdR](#):
>
> So ST is using regexes then

Hi Richard

ST does have some Regex functionality but I had not thought of these new Character Range methods (introduced in version 3.70) in that light. I guess you could think of the character ranges as either having been borrowed from regex or alternatively implementing a very small subset of regex, but really it was just an abbreviation as I found typing out all the characters tedious and potentially error-prone and the alternative of writing a loop dealing with one character at a time seemed less than ideal.

> [@RchdR](#):
>
> Are any of the methods that use regex labelled?

I see you have started another thread which is a good idea as we are having thread drift here and being off-topic so I will answer over there instead:

> [@StringTheory - Which methods can accept RegEx notation and any RegEx methods per se?](https://clarionhub.com/t/stringtheory-which-methods-can-accept-regex-notation-and-any-regex-methods-per-se/7575):
>
> Following on from @vitesse post which showed keepcharranges using a-z as a regex range, I wondered what other regex functionality exists. So looking through the docs I see a few like [https://www.capesoft.com/docs/stringtheory/StringTheory.htm#RegularExpressions](https://www.capesoft.com/docs/stringtheory/StringTheory.htm#RegularExpressions)[https://www.capesoft.com/docs/stringtheory/StringTheory.htm#Match](https://www.capesoft.com/docs/stringtheory/StringTheory.htm#Match)[https://www.capesoft.com/docs/stringtheory/StringTheory.htm#FindMatch](https://www.capesoft.com/docs/stringtheory/StringTheory.htm#FindMatch) But I wondered if the methods could be grouped so they stand out as ‘these are the regex/strpos me…

[Previous page](https://clarionhub.com/t/need-help-with-some-text-functions/3919.md?page=1)
