6-line procedure to convert to mixed case

Share your advanced PureBasic knowledge/code with the community.
The Mexican
User
User
Posts: 16
Joined: Sat Oct 07, 2006 5:47 pm
Location: Somewhere in Mexico

6-line procedure to convert to mixed case

Post by The Mexican »

I recently needed a procedure to convert words to Mixed Case. I checked the ones offered in this forum and I was amazed at the amount of code needed to do such thing. I created a 6 line procedure.

here it is:

Code: Select all

Procedure.s Word_Upper(st.s)
  
  For idx=1 To CountString(st," ")+1
    word.s=LCase(StringField(st,idx," "))
    ch.s=UCase(Left(word,1))
    finalword.s=ch + Right(word,Len(word)-1)
    mixed.s=mixed+finalword+" "
  Next
  
  ProcedureReturn Trim(mixed)
EndProcedure

example
this will give you the following:
Word_Upper("MariO prieto cAsTro") ---> Mario Prieto Castro

hope this will help somebody.
AND51
Addict
Addict
Posts: 1040
Joined: Sun Oct 15, 2006 8:56 pm
Location: Germany
Contact:

Post by AND51 »

Hi!

You are wrong! Your procedure has got 7 lines. You also have to count the "ProcedureReturn"-line!

I recommend you, to protect your variables by using "Protected".

Here is my version, it uses recursive calls instead of a FOR-Loop. I replaced Left() and Right() by PeekS(). If you use PeekS() with the right *pointer, then it's faster than Right() and Left(). Moreover, I don't use Trim() which makes my procedure even faster. Moreover, you can choose, which separator you want to youse.

Code: Select all

Procedure.s Capital_Letter(string.s, separator.s=" ")
	Protected word.s=StringField(string, 1, separator), recursive_call.s=PeekS(@string+Len(word)+1)
	word=UCase(PeekS(@word, 1))+LCase(PeekS(@word+1))
	If recursive_call
		word+separator+Capital_Letter(recursive_call, separator)
	EndIf
	ProcedureReturn word
EndProcedure

Debug Capital_Letter("the QUICK bRoWn fOx jUMPs ovER thE Lazy dog.")
Debug Capital_Letter("jackdaws+LOVE+my+bIg+sphinX+oF+quArZ.", "+")
A problem occured. Does anybody know, why there is garbage at the end of the debugged line?
When I compiled my code the first time, everything was ok. Second time, too. Then I changed the string and from now on, I get this:
Debugger wrote:The Quick Brown Fox Jumps Over The Lazy Dog. ) X)
Jackdaws+Love+My+Big+Sphinx+Of+Quarz.+L+Rx)+ç+)¼
Why? Before psoting this ocde, my code also supported Unicode (PeekS()), I removed this support due to this error.
PB 4.30

Code: Select all

onErrorGoto(?Fred)
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Post by srod »

The value of 'recursive_call' could contain a non-zero value even when it references a memory byte which is beyond the given string variable etc. It just depends what happens to be stored in the memory from previous operations etc.
I may look like a mule, but I'm not a complete ass.
Trond
Always Here
Always Here
Posts: 7446
Joined: Mon Sep 22, 2003 6:45 pm
Location: Norway

Post by Trond »

Two lines shorter (and 10 times slower):

Code: Select all

Procedure.s FixCase(St.s)
  St = " " + LCase(St)
  For I = 0 To 25
    ReplaceString(St, " " + Chr('a' + I), " " + Chr('A' + I), 2)
  Next
  ProcedureReturn Right(St, Len(St)-1)
EndProcedure
User avatar
Flype
Addict
Addict
Posts: 1542
Joined: Tue Jul 22, 2003 5:02 pm
Location: In a long distant galaxy

Post by Flype »

hello,

here is a different version which works well :

Code: Select all

Procedure.s Capitalize(string.s, sep1.s = " ", sep2.s = " ") 
  Protected word.s = StringField(string, 1, sep1)
  If word 
    word = UCase(Left(word, 1)) + LCase(Right(word, Len(word) - 1))
    ProcedureReturn word + sep2 + Capitalize(Right(string, Len(string) - Len(word) - 1), sep1, sep2)
  EndIf
EndProcedure 

Debug Capitalize("the QUICK bRoWn fOx jUMPs ovER thE Lazy dog.")
Debug Capitalize("jackdaws+LOVE+my+bIg+sphinX+oF+quArZ.", "+")
but well, while doing this procedure i experimented a unicode-related problem :
Try first with unicode 'OFF' and then retry with unicode 'ON',

Code: Select all

string$ = "hello!"

Debug UCase(Left(string$, 1)) + LCase(Right(string$, Len(string$) - 1)) ; Output should be 'Hello!'
No programming language is perfect. There is not even a single best language.
There are only languages well suited or perhaps poorly suited for particular purposes. Herbert Mayer
User avatar
Flype
Addict
Addict
Posts: 1542
Joined: Tue Jul 22, 2003 5:02 pm
Location: In a long distant galaxy

Post by Flype »

Trond wrote:Two lines shorter (and 10 times slower):

Code: Select all

Procedure.s FixCase(St.s)
  St = " " + LCase(St)
  For I = 0 To 25
    ReplaceString(St, " " + Chr('a' + I), " " + Chr('A' + I), 2)
  Next
  ProcedureReturn Right(St, Len(St)-1)
EndProcedure
Well done Trond. And it is Unicode compatible :!:


just a little modification to have the separator argument :

Code: Select all

Procedure.s Capitalize(string.s, separator.s = " ")
  string = separator + LCase(string)
  For i = 0 To 25
    ReplaceString(string, separator + Chr('a' + i), separator + Chr('A' + i), 2)
  Next
  ProcedureReturn Right(string, Len(string) - 1)
EndProcedure

Debug Capitalize("the QUICK bRoWn fOx jUMPs ovER thE Lazy dog.")
Debug Capitalize("jackdaws+LOVE+my+bIg+sphinX+oF+quArZ.", "+")
No programming language is perfect. There is not even a single best language.
There are only languages well suited or perhaps poorly suited for particular purposes. Herbert Mayer
The Mexican
User
User
Posts: 16
Joined: Sat Oct 07, 2006 5:47 pm
Location: Somewhere in Mexico

Cannot compete

Post by The Mexican »

WOW guys, I guess there are many ways to do something in PB. Does speed matter anymore?

Probably the only difference between mine and the " faster" ones are a couple of microseconds, as far as speed goes!!

The record to break is the 7 line procedure from Flype!!
Can anybody come up with a 6 line procedure??
The Mexican
User
User
Posts: 16
Joined: Sat Oct 07, 2006 5:47 pm
Location: Somewhere in Mexico

wrong person

Post by The Mexican »

In my last post I gave Flype credit for the 7 line procedure. Credit for this procedure goes to Trond.

Good job Trond.
User avatar
Flype
Addict
Addict
Posts: 1542
Joined: Tue Jul 22, 2003 5:02 pm
Location: In a long distant galaxy

Post by Flype »

Does speed matter anymore?
yes of course, specially if you are processing a big strings.
but for tiny strings, about 20/30 words it is enough.
between mine and the " faster" ones are a couple of microseconds
1/
for this string "the QUICK bRoWn fOx jUMPs ovER thE Lazy dog."
yes it is a couple of microseconds but try with a big big string.
Trond's function should be much faster...

2/
in PureBasic, recursives procedures are always slower than a For/Next solution because of passing arguments (memory and stack management).
No programming language is perfect. There is not even a single best language.
There are only languages well suited or perhaps poorly suited for particular purposes. Herbert Mayer
Trond
Always Here
Always Here
Posts: 7446
Joined: Mon Sep 22, 2003 6:45 pm
Location: Norway

Post by Trond »

My functions is actually dreadfully slow...
Xombie
Addict
Addict
Posts: 898
Joined: Thu Jul 01, 2004 2:51 am
Location: Tacoma, WA
Contact:

Post by Xombie »

How about...

Code: Select all

Procedure Test(HoldString.l, AtPosition.l = 0, Delimiter.c = ' ')
   While PeekC(HoldString + (AtPosition << #PB_Compiler_Unicode))
      PokeC(HoldString + (AtPosition << #PB_Compiler_Unicode), Asc(LCase(Chr(PeekC(HoldString + (AtPosition << #PB_Compiler_Unicode))))) - (32 * ((AtPosition = 0) Or (PeekC(HoldString + ((AtPosition - 1) << #PB_Compiler_Unicode)) = Delimiter))))
      AtPosition + 1
   Wend
EndProcedure
Testing against...

Code: Select all

a.s = "the QUICK bRoWn fOx jUMPs ovER thE Lazy dog."
Debug a + " : " + Str(Len(a))
Test(@a)
Debug a + " : " + Str(Len(a))
a.s = "jackdaws+LOVE+my+bIg+sphinX+oF+quArZ."
Debug a + " : " + Str(Len(a))
Test(@a, 0, '+')
Debug a + " : " + Str(Len(a))
... for 6 very ugly lines? :) I also added in a delimiter option like Flype's code. You can also set the start index for capitalizing. And it should be unicode compatible. Running a quick test of 100,000 items (all the same 'quick brown fox...' line) shows a rough time of 344 ms which isn't too bad.
User avatar
Flype
Addict
Addict
Posts: 1542
Joined: Tue Jul 22, 2003 5:02 pm
Location: In a long distant galaxy

Post by Flype »

what about this one : ok it is 10 lines but it is as fast as short ! because there's absolutely no use of purebasic's string functions.

Code: Select all

Procedure.s Capitalize(string.s, sep.c = ' ') ; Capitalize each word of the given string - Unicode Compatible. 
  Protected last.c = sep, *s.Character = @string 
  While *s\c 
    If last = sep 
      If *s\c >= 'a' And *s\c <= 'z' : *s\c - 32 : EndIf 
    Else
      If *s\c >= 'A' And *s\c <= 'Z' : *s\c + 32 : EndIf 
    EndIf 
    last = *s\c : *s + SizeOf(Character) 
  Wend 
  ProcedureReturn string 
EndProcedure 

Debug Capitalize("the QUICK bRoWn fOx jUMPs ovER thE Lazy dog.")
Debug Capitalize("jackdaws+LOVE+my+bIg+sphinX+oF+quArZ.", '+')
No programming language is perfect. There is not even a single best language.
There are only languages well suited or perhaps poorly suited for particular purposes. Herbert Mayer
Xombie
Addict
Addict
Posts: 898
Joined: Thu Jul 01, 2004 2:51 am
Location: Tacoma, WA
Contact:

Post by Xombie »

I count 18 lines, Flype :) And it was about getting it down in a few lines, not necessarily speed optimized. Come on~~ 6 lines or less~~ :D
Trond
Always Here
Always Here
Posts: 7446
Joined: Mon Sep 22, 2003 6:45 pm
Location: Norway

Post by Trond »

Code: Select all

Procedure Test(HoldString.l, AtPosition.l = 0, Delimiter.c = ' ') 
   While PeekC(HoldString + (AtPosition << #PB_Compiler_Unicode)) 
      PokeC(HoldString + (AtPosition << #PB_Compiler_Unicode), Asc(LCase(Chr(PeekC(HoldString + (AtPosition << #PB_Compiler_Unicode))))) - (32 * ((AtPosition = 0) Or (PeekC(HoldString + ((AtPosition - 1) << #PB_Compiler_Unicode)) = Delimiter)))) 
      AtPosition + 1 
   Wend 
EndProcedure
Hey changing the parameter type of the string is cheating!
User avatar
Flype
Addict
Addict
Posts: 1542
Joined: Tue Jul 22, 2003 5:02 pm
Location: In a long distant galaxy

Post by Flype »

Xombie wrote:I count 18 lines, Flype :) And it was about getting it down in a few lines, not necessarily speed optimized. Come on~~ 6 lines or less~~ :D
so, even if i like mine, i must say that your procedure seems unbeatable :twisted:
No programming language is perfect. There is not even a single best language.
There are only languages well suited or perhaps poorly suited for particular purposes. Herbert Mayer
Post Reply