Resolved Returning an index from a string character

Discussion in 'iOS Programming' started by charmofmaking, May 17, 2013.

  1. charmofmaking, May 17, 2013
    Last edited: Jun 1, 2013

    charmofmaking macrumors member

    Joined:
    Feb 2, 2013
    #1
    I am setting an index within a sprite sheet based on reading each character in a string of text.

    So @"ABC" returns 12,13,14 and so on... The code below works but is there a simple (better) way of doing this?

    I seems to remember CHR$() and the such like from BBC BASIC but I am struggling to find anything like that for NSString.

    Code:
    //default to char space
    spriteTextureX[s]=38;spriteTextureY[s]=2;spriteTextureS[s]=textureSize32;//NOT default 128
    						
    if(messageCharPos<messageLen){
                    
    	    NSString *aChar = [messageText substringWithRange:NSMakeRange(messageCharPos, 1)];
    						
    	    //NSLog(@"char at pos %i is %@",messageCharPos,aChar);
    						    
    	    if([@"A" isEqualToString:aChar]) {spriteTextureX[s]=12;}
    	    if([@"B" isEqualToString:aChar]) {spriteTextureX[s]=13;}
    	    if([@"C" isEqualToString:aChar]) {spriteTextureX[s]=14;}
    	    // and so on...
    
    	    messageX+=32;//inc x
    	    messageCharPos++;//inc pos along the string						    
    						           
    }//endif within len of string
    
    Hope someone can help :confused:
     
  2. robbieduncan Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #2
    Do you absolutely, definitely have to use a NSString or would a char[] be acceptable? All those expensive method calls to essentially use a NSString as an array!
     
  3. PhoneyDeveloper macrumors 68030

    PhoneyDeveloper

    Joined:
    Sep 2, 2008
    #3
    You can use a dictionary to associate the keys with the values: @"A" : [NSNumber numberWithInt:12]

    Code:
    NSInteger value = [[self.myDictionary objectForKey:aChar] integerValue];
    spriteTextureX[s]=value;
     
  4. charmofmaking thread starter macrumors member

    Joined:
    Feb 2, 2013
    #4
    Nice, so I could do something like

    Code:
    char alphaBet [] = "ABC";
    int base = 12;
    for (int n=0; n<3; n++) {
       if([alphaBet[n] isEqualToString:aChar]) {spriteTextureX[s]=base+n;}
    }
    Is there a simpler way to compare the two strings instead of isEqualToString?


     
  5. Duncan C macrumors 6502a

    Duncan C

    Joined:
    Jan 21, 2008
    Location:
    Northern Virginia
    #5
    For single characters, you should use arrays of unichar, and characterAtIndex to extract a character from a string.

    With the unichar data type you can use == to compare characters. (Unless you need to ignore case or diacritical marks or something like that.
     
  6. PhoneyDeveloper macrumors 68030

    PhoneyDeveloper

    Joined:
    Sep 2, 2008
    #6
    If your string is pure ascii then all you need is a lookup table. This would be a 256 char array with the correct value in each member. If your string is not pure ascii you should probably use a dictionary like I mentioned earlier.

    Code:
    int value = myArray[achar];
    spritTextureX[s] = value;
    
    Unless you are an expert in unicode you should not use the unichar data type or characterAtIndex.
     
  7. Duncan C macrumors 6502a

    Duncan C

    Joined:
    Jan 21, 2008
    Location:
    Northern Virginia
    #7

    Umm, why? The unichar type is a simple scalar data type, and characterAtIndex returns a single character. Why does that require expert-level knowledge?
     
  8. ArtOfWarfare macrumors 604

    ArtOfWarfare

    Joined:
    Nov 26, 2007
    #8
    I might be mistaken, but I thought there were a lot of unichars that occupy more than one index, IE, a lot of the emoji characters take up two indices.
     
  9. Duncan C macrumors 6502a

    Duncan C

    Joined:
    Jan 21, 2008
    Location:
    Northern Virginia
    #9
    Take up two indices? No.

    Unicode is a 16 bit character set. Unichars are 16 bits.

    Some encodings like UTF8 play games where standard ASCII (Unicode page 0) characters only take 8 bits, and other characters are encoded using multiple 8-bit characters. (Kind of like the way BASE64 encoding converts binary data into the 64 ASCII characters that you can send through any brain-damaged EBCDIC/7-bit ASCII computer from the 1960s.)

    However, NSString hides that mess from you. You can just treat an NSString as an array of 16-bit unicode characters and it all works perfectly. Then, when you want to save it to a file, you save it using an encoding like UTF8, and it handles THAT for you too.
     
  10. chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #10
    No. For example, emoticons:
    There are other less trivial examples, such as Egyptian hieroglyphs and Deseret.

    Full list of code charts in PDF:
    http://www.unicode.org/charts/PDF/

    Any chart with more than 4 hex digits is necessarily outside the Basic Multilingual Plane, i.e. requires more than 16 bits.
    http://en.wikipedia.org/wiki/Unicode_plane

    If you mean the C typedef (spelled 'unichar', all lower-case), then yes. But not every Unicode code-point can be represented as a single unichar. See the UTF-16 encoding.


    Standard ASCII is a 7-bit code. So it only takes 7 bits, not 8.
    http://en.wikipedia.org/wiki/ASCII
     
  11. ArtOfWarfare macrumors 604

    ArtOfWarfare

    Joined:
    Nov 26, 2007
    #11
    I feel smart now that chown33 has backed up what I said.
     
  12. chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #12
    And then the feeling wears off and all you're left with is a penchant for regular expressions and sarcasm.
     
  13. PhoneyDeveloper macrumors 68030

    PhoneyDeveloper

    Joined:
    Sep 2, 2008
    #13
    Do you know what a combining character is? precomposed, decomposed characters?

    Some characters can be represented in multiple ways. characterAtIndex will allow you to shoot yourself in the foot, unless you're an expert. You can be lucky for a little while, then get shot.
     
  14. Duncan C macrumors 6502a

    Duncan C

    Joined:
    Jan 21, 2008
    Location:
    Northern Virginia
    #14

    I stand corrected.
     
  15. MattInOz macrumors 68030

    MattInOz

    Joined:
    Jan 19, 2006
    Location:
    Sydney
    #15
    Sorry if i'm missing something but....

    Isn't that sort of irrelevant if the OP has control over the strings of text used to index the sprite table?

    If one of those characters got in it's going to produce an out range error on the sprite look up if the original code is anything to go by.

    Why not just make the strings so that -characterAtIndex returns a unichar of the right integer value (typedef unsigned short unichar)?
    Or have an offset by creating a variable of the unichar at the zero index (i.e. 'a') then minus that from the result to find a location in the sprite table.
     
  16. PhoneyDeveloper macrumors 68030

    PhoneyDeveloper

    Joined:
    Sep 2, 2008
    #16
    IMO, it's a slippery slope. It's possible that if the characters are known to be only ascii then there would be no problem. I don't see the advantage over using the dictionary like I mentioned. If the letters are typed in I don't see how they're restricted to ascii. If they're not typed in then I don't see the problem.

    Having said that, I don't really understand how letters that are typed in correspond to indexes into a sprite sheet.
     
  17. xArtx macrumors 6502a

    Joined:
    Mar 30, 2012
    #17
    So long as it's guaranteed ASCII, am I missing something here?

    Code:
    if (messageCharPos<messageLen){
    spriteTextureX[s] = char_youre_looking_at - 53; // ("A",41h,65d) - 53 = 12.
    }                                               // ("B",42h,66d) - 53 = 13, etc.
    
    and handle character that is unsupported in your spritesheet..

    Code:
    if (spriteTextureX[s] > lowerbound || spriteTextureX[s] > upperbound) {
    // point to spritesheet address for unsupported characters, like a space.
    }
    
    Since you called it a "message" I'm guessing input comes from the program itself, and is ASCII.
     
  18. charmofmaking thread starter macrumors member

    Joined:
    Feb 2, 2013
    #18
    Yes it is ASCII so if there is a simple way to get the ASCII code of a single character held in aChar string that would be perfect...

    Code:
    NSString *aChar = [messageText substringWithRange:NSMakeRange(messageCharPos, 1)];
    
    INT what_to_put_here = ??????; //ASCII code of aChar string
    
    //NSLog(@"char at pos %i is %@ with ASCII code of %i",messageCharPos,aChar,what_to_put_here);
    
    So the question is how do I return an integer containing the ASCII code of aChar in the code above?



     
  19. robbieduncan Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #19
    I come back to my question right at the top: do you absolutely have to use NSString? Or can you use an old-school C string/character array?
     
  20. Duncan C macrumors 6502a

    Duncan C

    Joined:
    Jan 21, 2008
    Location:
    Northern Virginia
    #20

    Since it's guaranteed to be ASCII, use charAtIndex, which returns a unichar. For ASCII characters, the value of the unichar will be the ASCII code of the character.

    Something like this:

    Code:
    for (int index = 0; index < messageText.length; index++)
    {
      unichar aChar = [messageText characterAtIndex];
      NSLog(@"Character at index %d = %d", index, aChar);
    }
     
  21. charmofmaking thread starter macrumors member

    Joined:
    Feb 2, 2013
    #21
    I create the string so it could be NSless. If there is a pure and simple way to walk through a string and return the ASCII of each character as an int that would be very interesting.



    ----------

    Finally got there!

    It seems that my continued failure to grasp C makes the sucessful builds all the sweeter :D

    output:
    char at pos 0 is A with code of 65 as int 65
    char at pos 1 is B with code of 66 as int 66
    char at pos 2 is C with code of 67 as int 67

    from:
    Code:
    //get character at pos
    NSString *aChar = [gameMessageText substringWithRange:NSMakeRange(messageCharPos, 1)];
                
    //get ASCII code of character at pos
    NSNumber *aCode = [NSNumber numberWithUnsignedChar:[gameMessageText characterAtIndex:messageCharPos]];
                                
    //and now as an integer 
    int aInt = [aCode intValue];
                                
    //good news everyone!
    NSLog(@"char at pos %i is %@ with code of %@ as int %i",messageCharPos,aChar,aCode,aInt);
    

     
  22. Duncan C macrumors 6502a

    Duncan C

    Joined:
    Jan 21, 2008
    Location:
    Northern Virginia
    #22
    A unichar is a typedef for unsigned short. (a short unsigned integer). There is no reason to create an NSNumber and get it's intVAlue, and this will create an extra object for every character you parse.

    You are also creating an unneeded single-character string object for every time this code is called.

    Memory allocation is expensive, so creating an object for every character will be slow. If you are parsing thousands of characters it will start bogging your program down.

    All that code could be replaced with:

    Code:
    unichar aChar = [gameMessageText characterAtIndex: 0];
    NSLog(@"char at pos %i is %@ with code of %@ as int %i",messageCharPos,aChar,aCode,aInt);
    
     
  23. chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #23
    The red-hilited format specifier is wrong. %@ is for objects. The unichar type is not an object type. Use %C instead.

    The blue-hilited format specifier presumes the existence of an aCode object. Which was eliminated as superfluous. So simply take out anything dealing with aCode. The "code" of a unichar is its numeric value, which is already being logged as %i. One could also show the code as hex (%x), but as long as aCode doesn't exist, it can't be logged.


    https://developer.apple.com/library...eptual/Strings/Articles/formatSpecifiers.html


    You should spend the time needed to remedy the C deficit.
     
  24. Duncan C macrumors 6502a

    Duncan C

    Joined:
    Jan 21, 2008
    Location:
    Northern Virginia
    #24

    Oops. I didn't pay any attention to the log statement, and just copy-and-pasted it from the OP's post. Good catch.
     
  25. charmofmaking thread starter macrumors member

    Joined:
    Feb 2, 2013
    #25
    output:
    aUni is a short unsigned int of 65 representing A
    aUni is a short unsigned int of 66 representing B
    aUni is a short unsigned int of 67 representing C

    from:
    Code:
    unichar aUni = [gameMessageText characterAtIndex: messageCharPos];
    NSLog(@"aUni is a short unsigned int of %u representing %C",aUni,aUni);
    Perfect :D Thank you for taking the time to help me out, its much appreciated.

     

Share This Page