News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Changing to Lower case

Started by Pro32, February 19, 2005, 11:53:17 PM

Previous topic - Next topic

Pro32

I been having trouble. I want to change my sentence to lower case except for the first letter in each word. I been told to campare it to a space (20h) but I don't know how to do it. Help anyone?? Thanks in advance.


.data

sentence BYTE "CHANGE TO LOWER CASE!!"
sentence1 BYTE 30 DUP (?)

.code
main PROC
   ;this prints the original sentence
   mov edx, OFFSET sentence
   call WriteString
   call Crlf


   ;Print sentence in  Lowercase letters
   mov ecx, LENGTHOF sentence1
   mov esi, 0
   mov al,0      

L1:
   mov al, sentence[esi]
   cmp esi,0
   je NoUpperCase ;for the first symbol
   cmp al,41h
   jl NoUpperCase ; if less then 'A'
   cmp al,5ah
   jg NoUpperCase  ;if greater then 'Z'
   add al,32d


NoUpperCase:
   mov sentence[esi], al
   inc esi
   ;mov edx, OFFSET sentence   
   loop L1
      

   call WriteString
   call Crlf

   exit
main ENDP
END main

MichaelW

To determine if the character is above 'Z', compare it to the character code for 'Z':

cmp al,'Z'
ja  NoUpperCase


eschew obfuscation

pbrennick

Pro32,
Here is a procedure that is flag driven:

If flag = 3 then invert case, if upper convert selected text to lower or if lower convert selected text to upper.
If flag = 2 then convert selected text to upper.
If flag = 1 then convert selected text to lower.

ChangeCase proc
;---------------------------------------
        inv  SendMessage, hREdit, EM_EXGETSEL, 0, offset cr   ; Get start and ending positions of highlighted text
        mov eax, cr.cpMax               ; Get end position
        sub eax, cr.cpMin               ; Minus the start position
        .if eax < 255                   ; If in range...
          inv  SendMessage, hREdit, EM_GETSELTEXT, 0, addr szFlipCase     ; Get selected text
        .endif                          ; End of conditional
        push edi                        ; Register preservation
        mov edi, Offset szFlipCase      ; Pointer to text selection storage buffer
J001:   mov al, [edi]                   ; Get a character
        .if Flag == 3                   ; Invert selected text
          .if al >= 'A' && al <= 'Z'    ; If upper case...
            or byte ptr [edi], 20h      ; Convert it to lower case
          .elseif al >= 'a' && al <= 'z'    ; If lower case...
            and byte ptr [edi], 5fh     ; Convert it to upper case
          .endif                        ; End of conditional
        .elseif Flag == 2               ; Convert selected text to upper case
          .if al >= 'a' && al <= 'z'    ; If lower case...
            and byte ptr [edi], 5fh     ; Convert it to upper case
          .endif                        ; End of conditional
        .elseif Flag == 1               ; Convert selected text to lower
          .if al >= 'A' && al <= 'Z'    ; If upper case...
            or byte ptr [edi], 20h      ; Convert it to lower case
          .endif                        ; End of conditional
        .endif                          ; End of conditional
        inc edi                         ; Update the buffer pointer
        or al, al                       ; Done?
        jne J001                        ; Continue until ASCIIZ is reached
        pop edi                         ; Restore the register
;       Put back the reconditioned text
        inv  SendMessage, hREdit, EM_REPLACESEL, TRUE, addr szFlipCase
        ret                             ; Return to caller
;---------------------------------------
ChangeCase endp


Paul

donkey

#3
If size is not a factor you might think about using a table and XLATB. It is fairly fast once the table is in the data cache...

align 16
lcase:
db   0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15
db  16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
db  32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47
db  48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63
db  64, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111
db 112,113,114,115,116,117,118,119,120,121,122, 91, 92, 93, 94, 95
db  96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111
db 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127
db 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143
db 144,145,146,147,148,149,150,151,152,153,154,155,156,156,158,159
db 160,161,162,163,164,165,166,167,168,169,170,171,172,173,173,175
db 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191
db 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207
db 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223
db 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239
db 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255


lszCase FRAME pString
uses ebx,esi,edi

mov ebx,offset lcase

mov edi,[pString]
mov esi,[pString]
xor ecx,ecx
:
mov al,[esi+ecx]
xlatb
mov [edi+ecx],al
inc ecx
or al,al
jnz <
:

mov eax,edi
RET
ENDF


For upper case use the same routine but change the table...

align 16
ucase:
db   0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15
db  16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
db  32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47
db  48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63
db  64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79
db  80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95
db  96, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79
db  80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90,123,124,125,126,127
db 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143
db 144,145,146,147,148,149,150,151,152,153,154,155,156,156,158,159
db 160,161,162,163,164,165,166,167,168,169,170,171,172,173,173,175
db 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191
db 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207
db 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223
db 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239
db 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

pbrennick

Nowadays with the extreme disk sizes we get to play with, size is no longer much of an issue.  Tables are pretty fast, too, Donkey?

Paul

donkey

I think they are a little slow generally but I would imagine that they must be faster than a large grouping of compares and jumps. I usually use the table method as in reality there is never too much data to translate, a few hundred chars at the most. I would think that the programmatic method would be faster on small strings, I have never really tested it.
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

raymond

Pro32

To answer your question, add the following instructions just before you change from upper to lower case:

cmp  byte ptr[esi-1]," "  ;checks if previous character was a space
jz   NoUpperCase          ;don't change the 1st letter of a word


Raymond
When you assume something, you risk being wrong half the time
http://www.ray.masmcode.com

Randall Hyde

Quote from: Pro32 on February 19, 2005, 11:53:17 PM
I been having trouble. I want to change my sentence to lower case except for the first letter in each word. I been told to campare it to a space (20h) but I don't know how to do it. Help anyone?? Thanks in advance.

Actually, the more difficult problem is figuring out what is the first character of each word.  Different people have different ideas about what constitutes a "word". So you should specify that first.  After you can pick out individual words from a string, then the lower case conversion is easy.

BTW, do you *ignore* the first character of each word, or do you convert it to upper case?
Cheers,
Randy Hyde

Pro32

#8
Quote from: raymond on February 20, 2005, 04:39:00 AM
Pro32

To answer your question, add the following instructions just before you change from upper to lower case:

cmp  byte ptr[esi-1]," "  ;checks if previous character was a space
jz   NoUpperCase          ;don't change the 1st letter of a word


Raymond


I've tried adding those lines but it crashes my program. Where exactly do I put it...and what goes in between the quotation marks... I think I have an idea of where your going so this helps a lot. Thanks

Pro32

Quote from: Randall Hyde on February 20, 2005, 05:36:20 AM
Quote from: Pro32 on February 19, 2005, 11:53:17 PM
I been having trouble. I want to change my sentence to lower case except for the first letter in each word. I been told to campare it to a space (20h) but I don't know how to do it. Help anyone?? Thanks in advance.

Actually, the more difficult problem is figuring out what is the first character of each word.  Different people have different ideas about what constitutes a "word". So you should specify that first.  After you can pick out individual words from a string, then the lower case conversion is easy.

BTW, do you *ignore* the first character of each word, or do you convert it to upper case?
Cheers,
Randy Hyde


I want to ignore it because its already in Upper Case.

raymond

QuoteI've tried adding those lines but it crashes my program. Where exactly do I put it...and what goes in between the quotation marks... I think I have an idea of where your going so this helps a lot. Thanks

You can use characters between quotation marks and they will be interpreted by the assembler as their ASCII code. MichaelW provided you with an example:
cmp al,"Z" is the same as cmp al,5ah.
And " " is the same as using 20h.

Using such technique makes the code easier to visualize and you don't need to refer to an ASCII conversion table for all the characters.

If you have not changed the code you originally posted, the instructions I suggested would go immediately before the add al,32d. And I can't see why the program should crash unless you did change that original code.

Raymond

P.S. You should also start practicing the use of null-terminated strings. Those are a necessity if you intend to use a lot of the Windows API functions. It's also a lot easier to detect the end of a string instead of relying on the count of characters returned by LENGTHOF and then using either a register or memory to keep track of it.
When you assume something, you risk being wrong half the time
http://www.ray.masmcode.com

Pro32

Quote from: raymond on February 20, 2005, 05:36:44 PM
QuoteI've tried adding those lines but it crashes my program. Where exactly do I put it...and what goes in between the quotation marks... I think I have an idea of where your going so this helps a lot. Thanks

You can use characters between quotation marks and they will be interpreted by the assembler as their ASCII code. MichaelW provided you with an example:
cmp al,"Z" is the same as cmp al,5ah.
And " " is the same as using 20h.

Using such technique makes the code easier to visualize and you don't need to refer to an ASCII conversion table for all the characters.

If you have not changed the code you originally posted, the instructions I suggested would go immediately before the add al,32d. And I can't see why the program should crash unless you did change that original code.

Raymond

P.S. You should also start practicing the use of null-terminated strings. Those are a necessity if you intend to use a lot of the Windows API functions. It's also a lot easier to detect the end of a string instead of relying on the count of characters returned by LENGTHOF and then using either a register or memory to keep track of it.


It works! I just had to tweek your code a bit.  I'm using registry to store characters because I'm new to this language. I hope I'll get better with the help of this community. Thanks a bunch.