Page 1 of 3
6-line procedure to convert to mixed case
Posted: Tue Nov 07, 2006 6:41 am
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.
Posted: Tue Nov 07, 2006 2:16 pm
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.
Posted: Tue Nov 07, 2006 2:56 pm
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.
Posted: Tue Nov 07, 2006 3:40 pm
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
Posted: Tue Nov 07, 2006 3:45 pm
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!'
Posted: Tue Nov 07, 2006 3:55 pm
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.", "+")
Cannot compete
Posted: Tue Nov 07, 2006 4:58 pm
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??
wrong person
Posted: Tue Nov 07, 2006 5:01 pm
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.
Posted: Tue Nov 07, 2006 5:07 pm
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).
Posted: Tue Nov 07, 2006 5:14 pm
by Trond
My functions is actually dreadfully slow...
Posted: Tue Nov 07, 2006 7:44 pm
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.
Posted: Tue Nov 07, 2006 7:50 pm
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.", '+')
Posted: Tue Nov 07, 2006 8:08 pm
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~~

Posted: Tue Nov 07, 2006 8:24 pm
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!
Posted: Tue Nov 07, 2006 8:33 pm
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~~

so, even if i like mine, i must say that your procedure seems unbeatable
