Can someone explain this code
- (IBAction)backspacePressed {
self.display.text =[self.display.text substringToIndex:
[self.display.text length] - 1];
if ( [self.display.text isEqualToString:#""]
|| [self.display.text isEqualToString:#"-"]) {
self.display.text = #"0";
self.userIsInTheMiddleOfEnteringNumber = NO;
}
}
I don't get what the 2 lines mean in objective c. || Also, I don't get the meaning of substringToIndex. How does a programmer know to use substringToIndex out of all the different methods in the documentation I saw substringFromIndex etc. There are so many. Is this saying that the strings in the index are counted and -1 means it deletes a string? How would the meaning in the apples documentation relate to deleting a character ?
Comments supplied with explanation of code...
- (IBAction)backspacePressed
{
// This is setting the contents of self.display (a UITextField I expect) to
// its former string, less the last character. It has a bug, in that what
// happens if the field is empty and length == 0? I don't think substringToIndex
// will like being passed -1...
self.display.text =[self.display.text substringToIndex:
[self.display.text length] - 1];
// This tests if the (now modified) text is empty (better is to use the length
// method) or just contains "-", and if so sets the text to "0", and sets some
// other instance variable, the meaning of which is unknown without further code.
if ( [self.display.text isEqualToString:#""]
|| [self.display.text isEqualToString:#"-"]) {
self.display.text = #"0";
self.userIsInTheMiddleOfEnteringNumber = NO;
}
}
|| is an OR operator. At least one of the statements has to be true.
Look at Apple's documentation for the substringToIndex: method
https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/Reference/NSString.html
This is stuff you could find easily with a google search.
Related
please help me with this problem.
I want to check if the targetString match the keyword or not. Consider some character may different, but should still return true.
Example:
targetString = #"#ß<"
keyword = #"abc", #"∂B(", #"#Aß<"
result: all must return true.
(Matched.targetString and all keyword are the same.)
Consider me have an array, contains list of character set that can be the same:
NSArray *variants = [NSArray arrayWithObjects:#"aA#∂", #"bBß", #"c©C<(", nil]
So that when matching, with this rule, it can match as the example above.
Here is what i've done so far (using recursion):
- (BOOL) test:(NSString*)aString include:(NSString*) keyWord doTrim:(BOOL)doTrim {
// break recursion.
if([aString length] < [keyWord length]) return false;
// First, loop through each keyword's character
for (NSUInteger i = 0; i < [keyWord length]; i++) {
// Get #"aA#∂", #"bBß", #"c©C<(" or only the character itself.
// like, if the keyword's character is A, return the string #"aA#∂".
// If the character is not in the variants set, eg. P, return #"P"
char c = [keyWord characterAtIndex:i];
NSString *rs = [self variantsWithChar:c];
// Check if rs (#"aA#∂" or #"P") contains aString[i] character
if([rs rangeOfString:[NSString stringWithCharacters:[aString characterAtIndex:i] length:1]].location == NSNotFound) {
// If not the same char, remove first char in targetString (aString), recursion to match again.
return [self test:[aString substringFromIndex:1] include:keyWord doTrim:NO];
}
}
// If all match with keyword, return true.
return true;
}
- (NSString *) variantsWithChar:(char) c {
for (NSString *s in self.variants) {
if ([s rangeOfString:[NSString stringWithFormat:#"%c",c]].location != NSNotFound) {
return s;
}
}
return [NSString stringWithFormat:#"%c", c];
}
The main problem is, variantsWithChar: doesn't return the correct string. I don't know which datatype and which function should I use here. Please help.
For thou who know ruby, here's the example in ruby. It work super fine!
require 'test/unit/assertions'
include Test::Unit::Assertions
class String
def matching?(keyword)
length >= keyword.length && (keyword.chars.zip(chars).all? { |cs| variants(cs[0]).include?(cs[1]) } || slice(1, length - 1).matching?(keyword))
end
private
VARIANTS = ["aA#∂", "bBß", "c©C<("]
def variants(c)
VARIANTS.find { |cs| cs.include?(c) } || c
end
end
assert "abc".matching?("#ß<")
PS: The fact is, it's containt a japanese character set that sounds the same (like あア, いイ... for thou who know japanese)
PS 2: Please feel free to edit this Question, since my engrish is sooo bad. I may not tell all my thought.
PS 3: And, maybe some may comment about the performance. Like, search about 10,000 target words, with nearly 100 variants, each variant have at most 4 more same characters.
So first off, ignore comments about ASCII and stop using char. NSString and CFString use unichar
If what you really want to do is transpose hiragana and katakana you can do that with CFStringTransform()
It wraps the ICU libraries included in OS X and iOS.
It makes it very simple.
Search for that function and you will find examples of how to use it.
After a while (a day) working on the code above, I finally get it through. But don't know about the performance. Someone comment and help me improve about performance, please. Thanks.
- (BOOL) test:(NSString*)aString include:(NSString*) keyWord doTrim:(BOOL)doTrim {
// break recursion.
if([aString length] < [keyWord length]) return false;
// First, loop through each keyword's character
for (NSUInteger i = 0; i < [keyWord length]; i++) {
// Get #"aA#∂", #"bBß", #"c©C<(" or only the character itself.
// like, if the keyword's character is A, return the string #"aA#∂".
// If the character is not in the variants set, eg. P, return #"P"
NSString* c = [NSString stringWithFormat:#"%C", [keyWord characterAtIndex:i]];
NSString *rs = [self variantsWithChar:c];
NSString *theTargetChar = [NSString stringWithFormat:#"%C", [aString characterAtIndex:i]];
// Check if rs (#"aA#∂" or #"P") contains aString[i] character
if([rs rangeOfString:theTargetChar].location == NSNotFound) {
// If not the same char, remove first char in targetString (aString), recursion to match again.
return [self test:[aString substringFromIndex:1] include:keyWord doTrim:NO];
}
}
// If all match with keyword, return true.
return true;
}
If you remove all comment, it'll be pretty short...
////////////////////////////////////////
- (NSString *) variantsWithChar:(NSString *) c{
for (NSString *s in self.variants) {
if ([s rangeOfString:c].location != NSNotFound) {
return s;
}
}
return c;
}
You could try comparing ascii values of the japanese characters in the variants's each character's ascii value. These japanese characters aren't treated like usual characters or string. Hence, string functions like rangeOfString won't work on them.
to be more precise: have a look at the following code.
it will search for "∂" in the string "aA#∂"
NSString *string = #"aA#∂";
NSMutableSet *listOfAsciiValuesOfString = [self getListOfAsciiValuesForString:string]; //method definition given below
NSString *charToSearch = #"∂";
NSNumber *ascii = [NSNumber numberWithInt:[charToSearch characterAtIndex:0]];
int countBeforeAdding = [listOfAsciiValuesOfString count],countAfterAdding = 0;
[listOfAsciiValuesOfString addObject:ascii];
countAfterAdding = [listOfAsciiValuesOfString count];
if(countAfterAdding == countBeforeAdding){ //element found
NSLog(#"element exists"); //return string
}else{
NSLog(#"Doesnt exists"); //return char
}
===================================
-(NSMutableSet*)getListOfAsciiValuesForString:(NSString*)string{
NSMutableSet *set = [[NSMutableSet alloc] init];
for(int i=0;i<[string length];i++){
NSNumber *ascii = [NSNumber numberWithInt:[string characterAtIndex:i]];
[set addObject:ascii];
}
return set;
}
My Mac app gets 2 string values from another app via scripting. Under certain conditions, the sender supplies "0-1". I need to detect this and blank the text box that displays it. The following, which only shows code for the second string, works in the debugger, but not when run outside it.
- (void)controlTextDidChange:(NSNotification *)notification
{
// there was a change in a text control
int tmpInt2 = 0;
NSMutableString *tmp2 = [NSMutableString stringWithString:[inputTextField2 stringValue]];
//NSLog(#"text box changed. value: %i", val);
if ([tmp2 length] > 3)
{
tmp2 = [NSMutableString stringWithString:[tmp2 substringToIndex:[tmp2 length] - 1]];
[inputTextField2 setStringValue:tmp2];
}
if ([tmp2 length] == 3)
{
tmpInt2 = [tmp2 intValue];
if (tmpInt2 > 360 || tmpInt2 < 0 || [tmp2 isEqualToString:#"0-1"])
{
//[self showAlert:#"Heading must be between 000 and 360"];
[inputTextField2 setStringValue:#""];
//[inputTextField2 setBackgroundColor:[NSColor yellowColor]];
[tmp2 setString:#""];
}
}
if ([[inputTextField2 stringValue] rangeOfCharacterFromSet:[[NSCharacterSet decimalDigitCharacterSet] invertedSet]].location != NSNotFound)
{
NSLog(#"This is not a positive integer");
//NSMutableString *strippedString = [NSMutableString stringWithCapacity:tmp.length];
[inputTextField2 setStringValue:#""];
//[[inputTextField2 cell] setBackgroundColor:[NSColor yellowColor]];
[tmp2 setString:#""];
}
/*
if ([tmp2 isEqualToString:#"0-1"])
{
[inputTextField2 setStringValue:#""];
[tmp2 setString:#""];
}
*/
if ([tmp2 rangeOfString:#"-"].location == NSNotFound) {
NSLog(#"string does not contain 0-1");
} else {
NSLog(#"string contains 0-1!");
[inputTextField2 setStringValue:#""];
[tmp2 setString:#""];
}
}
You should look into #trojanfoe's suggestion of using NSFormatter or one of its pre-defined subclasses. However you appear to misunderstand the purpose of NSMutableString, so I offer the following version of your code with some comments embedded. The text field used for the test was given a placeholder value of "Enter Heading", and it is assumed ARC is enabled. Modern property access syntax is used (object.property). HTH.
- (void)controlTextDidChange:(NSNotification *)notification
{
// there was a change in a text control
NSTextField *inputTextField = notification.object; // get the field
NSTextFieldCell *fieldCell = inputTextField.cell; // and its cell - we use the placeholder text for feedback in this sample
fieldCell.placeholderString = #"Enter heading"; // user has typed, restore default message
NSString *contents = inputTextField.stringValue; // an NSMutableString is not required, you never mutate this string
NSUInteger length = contents.length;
if (length > 3)
{
// remove last character - did you mean to truncate to three characters?
inputTextField.stringValue = [contents substringToIndex:length - 1];
}
else if (length == 3)
{
int tmpInt = contents.intValue;
if (tmpInt > 360 || tmpInt < 0 || [contents isEqualToString:#"0-1"])
{
fieldCell.placeholderString = #"Heading must be between 000 and 360"; // inform user why field was blanked
inputTextField.stringValue = #"";
}
}
else if ([contents rangeOfCharacterFromSet:[[NSCharacterSet decimalDigitCharacterSet] invertedSet]].location != NSNotFound)
{
// you might want different logic here
// if a user types "12Y" you delete everything, deleting just the "Y" might be more friendly
// ("Y" picked as an example as it could be a miss hit for the 6 or 7 keys)
fieldCell.placeholderString = #"Enter a positive integer"; // inform user why field was blanked
inputTextField.stringValue = #"";
}
}
Addendum - Comment Followup
Exactly what inputs you are expecting and what you wish to do with them is unclear. The first if just removes the last character from strings longer than 3 without doing any other checks. However I may have misinterpreted your intentions here, you have have intended to continue processing after that first if, e.g. something like:
...
if (length > 3)
{
// remove last character - did you mean to truncate to three characters?
contents = [contents substringToIndex:length - 1];
length -= 1;
}
if (length == 3)
{
...
Which means if your input is longer than 3 characters you remove the last (did you not want to simply truncate to 3? If so just change those two lines of code to do so) and then you continue with the following if/else.
I was writing a small Category on NSString, and I wanted to know if this method is accurately handles all potential use cases:
Update: to clarify -- I wanted to make sure I'm not missing some oddball case involving character encodings, etc..
#implementation NSString (Helpers)
+(BOOL)stringIsNilOrEmpty:(NSString*)aString {
if (!aString)
return YES;
return [aString isEqualToString:#""];
}
#end
Sample usage:
-(void) sampleUsage {
NSString *emptyString = #"";
NSString *nilString = nil;
NSAssert([NSString stringIsNilOrEmpty:nilString] == YES, #"String is nil/empty");
NSAssert([NSString stringIsNilOrEmpty:emptyString] == YES, #"String is nil/empty");
}
#end
I only use the next conditional and do not even need a category:
if (!aString.length)
{
...
}
Using Objective-C theory, a message to NIL will return nil or zero, so basically you do not have to test for nil.
You can simplify the code by removing conditional:
+(BOOL)stringIsNilOrEmpty:(NSString*)aString {
return !(aString && aString.length);
}
#dasblinkenlight's answer is fine, but a much more readable conditional check I would use is:
NSString *string = ...; // define the string
if ([string length] == 0) {
// Do stuff with the string
} else {
// The string is empty or nil here
}
Very concise and does not require a separate convenience function definition. It's easy enough to remember.
EDIT: #Michael G. Emmons posted this as the last comment to that answer... credit to him but I'm listing this as an answer in its own right.
Some examples of this sort of "is not empty or blank" tests as a category on NSString.
// Please note that in general I advocate using a prefix on category methods
// to avoid category collisions. I've not done this here for clarity.
// The #interface is also excluded from this example for brevity.
#implementation NSString (MyAdditions)
- (BOOL)isNotEmpty
{
return [self length] != 0;
}
- (BOOL)isNotBlank
{
if ([self isNotEmpty])
{
NSCharacterSet *nonWhitespaceSet = [[NSCharacterSet whitespaceAndNewlineCharacterSet] invertedSet];
NSRange range = [self rangeOfCharactersFromSet:nonWhitespaceSet];
return range.location != NSNotFound;
}
return NO;
}
#end
Simply Check your string length
> if (!yourString.length){
> //your code } a
message to NIL will return nil or 0, so no need to test for nil :).
Happy coding ...
Make sure to check for spaces, trim white spaces before calculating length.
+(BOOL)stringIsNilOrEmpty:(NSString*)aString {
return !aString || [[aString stringByTrimmingCharactersInSet:
[NSCharacterSet whitespaceCharacterSet]] length] == 0;
}
I'm trying to get the calculator app I've built to trigger some simple code if it detects I pushed the decimal point button (to only allow one decimal point per value). However, for some reason, these if statements regarding digit aren't being triggered. I've NSLogged the output of it and it is indeed showing as "." so I can't quite figure out why. I've changed the . to any other value too, nothing seems to trigger 'em.
NSString *digit = [sender currentTitle];
if (self.userIsInTheMiddleOfEnteringANumber) {
self.display.text = [[[self display] text] stringByAppendingString:digit]; // All in one line!
NSLog(#"Digit is equal to %#",digit);
if (digit == #".") NSLog(#"That was a decimal point!");
} else {
self.display.text = digit;
if (digit == #".") NSLog(#"You can't begin a number with a decimal!");
self.userIsInTheMiddleOfEnteringANumber = YES; // If they aren't typing, now they are!
}
Dont compare strings with ==. Use isEqualToString:
if ([digit isEqualToString:#"."])
== checks for pointer equality, not string equality.
== doesn't work:
if (digit == #".")
For string use:
if([digit isEqualToString:#".")
Hey folks, beneath is a piece of code i used for a school assignment.
Whenever I enter a word, with an O in it (which is a capital o), it fails!
Whenever there is one or more capital O's in this program, it returns false and logs : sentence not a palindrome.
A palindrome, for the people that dont know what a palindrome is, is a word that is the same read left from right, and backwards. (e.g. lol, kayak, reviver etc)
I found this bug when trying to check the 'oldest' palindrome ever found: SATOR AREPO TENET OPERA ROTAS.
When I change all the capital o's to lowercase o's, it works, and returns true.
Let me state clearly, with this piece of code ALL sentences/words with capital O's return false. A single capital o is enough to fail this program.
-(BOOL)testForPalindrome:(NSString *)s position:(NSInteger)pos {
NSString *string = s;
NSInteger position = pos;
NSInteger stringLength = [string length];
NSString *charOne = [string substringFromIndex:position];
charOne = [charOne substringToIndex:1];
NSString *charTwo = [string substringFromIndex:(stringLength - 1 - position)];
charTwo = [charTwo substringToIndex:1];
if(position > (stringLength / 2)) {
NSString *printableString = [NSString stringWithFormat:#"De following word or sentence is a palindrome: \n\n%#", string];
NSLog(#"%# is a palindrome.", string);
[textField setStringValue:printableString];
return YES;
}
if(charOne != charTwo) {
NSLog(#"%#, %#", charOne, charTwo);
NSLog(#"%i", position);
NSLog(#"%# is not a palindrome.", string);
return NO;
}
return [self testForPalindrome:string position:position+1];
}
So, is this some weird bug in Cocoa?
Or am I missing something?
B
This of course is not a bug in Cocoa, as you probably knew deep down inside.
Your compare method is causing this 'bug in Cocoa', you're comparing the addresses of charOne and charTwo. Instead you should compare the contents of the string with the isEqualToString message.
Use:
if(![charOne isEqualToString:charTwo]) {
Instead of:
if(charOne != charTwo) {
Edit: tested it in a test project and can confirm this is the problem.
Don't use charOne != charTwo
Instead use one of the NSString Compare Methods.
if ([charOne caseInsensitiveCompare:charTwo] != NSOrderedSame)
It may also have to do with localization (but I doubt it).