How to compare two strings while some parts of them are same?
Let say I have a string ABCAAAA.
For some reason, only ONE character of the string ABCAAAA can be changed at a time. For example, I can change this string to DBCAAAA.
Now the problem is :
How can I ensure ONLY ONE character is changed each time? Is there a method for NSString to compare how much two strings differ?
Purpose: I put each string into own UITextField to determine whether this one is editable if others had changed. I need to ensure only one is edited at a time. So if one had been edited, I will set UITextField's enable to NO to disable editing.
There is no built-in NSString method available to do what you want. You need to write your own method. Objective-C does let you "extend" classes with new methods to cover cases like this.
This is how I would do it:
#interface NSString(Extend)
-(NSInteger)proximity:(NSString*)otherString;
#end
#implementation NSString(Extend)
-(NSInteger)proximity:(NSString*)otherString
{
NSUInteger length = [otherString length];
if(length != [self length]) return -1;
NSUInteger k;
NSUInteger differences = 0;
for(k=0;k<length;++k)
{
unichar c1 = [self characterAtIndex:k];
unichar c2 = [otherString characterAtIndex:k];
if(c1!=c2)
{
++differences;
}
}
return differences;
}
#end
Then in my code at the place I wanted to check I would say something like
Michael L gave a good answer (+1)
I just wanted to note that if all your text strings are in separate UITextFields, then only one of them can be edited at a time. Therefore I really don't understand what you want to do with enable = NO part.
If text strings must be edited in certain order, just keep count of order by index by yourself.
Related
I am revising an early project where I use tags to identify 1-of-5, 1-of-16 or 1-of-10 UIButtons. I want to replace the tags with a customised property based on my understanding of this answer.
The property called myInfo consists of a string followed by an integer. This may well be a tag by another name but it makes a message source uniquely identifiable in a way that a simple integer tag does not, clearing magic numbers from my code and, hopefully, improving the documentation.
The property is created using a category
UIView+CustomProperties.m
#import "UIView+CustomProperties.h"
#implementation UIView (MyInfo)
-(void)setMyInfo:(id)info
{
objc_setAssociatedObject(self, "_myInfo", info, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
-(id)myInfo
{
return objc_getAssociatedObject(self, "_myInfo") ;
}
#end
And myInfo works when I import objc/runtime.h
UIView+CustomProperties.
#import <objc/runtime.h>
#interface UIView (MyInfo)
#property ( nonatomic, strong ) id myInfo;
#end
I call the category from the method (below) in the UIView where I create several sets of buttons.
// define type and number of 5, 16 or 10 buttons
switch (buttonCount) {
case 5:
roundButton.myInfo = [NSString stringWithFormat:#"transpose index %i", i ];
break;
case 16:
roundButton.myInfo = [NSString stringWithFormat:#"player index %i", i ];
break;
case 10:
roundButton.myInfo = [NSString stringWithFormat:#"note index %i", i ];
break;
default:
roundButton.myInfo = #“orphan button“;
break;
}
To identify a message source I have tried to strip away all non-numeric characters from myInfo using this method. However a problem appears in my selector method forButtons as I attempt to remove non-numeric characters
- (void)fromButtons:(UIButton*)button {
NSLog(#"Button %ld tapped", (long int)[button tag]);
NSLog(#"first, %#", button.myInfo);
NSString *newString = [[button.myInfo componentsSeparatedByCharactersInSet:
[[NSCharacterSet decimalDigitCharacterSet] invertedSet]]
componentsJoinedByString:#""];
NSLog(#"then, %#", newString);
NSLog(#"and %li", (long int)newString);
When I build and run and press button 1, the NSLog statements above produce the following log
2017-05-25 18:27:33.147 SatGam3[930:607301] Button 1 tapped
2017-05-25 18:27:33.147 SatGam3[930:607301] first, transpose index 1
2017-05-25 18:27:33.148 SatGam3[930:607301] then, 1
2017-05-25 18:27:33.148 SatGam3[930:607301] and 2070247168
Note that the long int value for the original tag is correct i.e. 1 whereas the long int recovered from the customised property is 2070247168.
Q.1 Firstly, is this approach correct ?
Q.2 If so, can someone please explain why am I extracting a 9-digit numeric value from myInfo ?
First, a problem that has nothing to do with your problem: Your use of "_myInfo" as the key here is slightly dangerous. In practice you're going to get away with it, but it relies on a compiler optimization that isn't promised. You're betting that the compiler (and possibly the linker) will ensure that all copies of the same constant string refer to the same memory location in the binary. That happens to be true, but it's not part of the language. Use a selector instead.
But that's not your problem. Your problem is this:
NSLog(#"and %li", (long int)newString);
newString is (unsurprisingly) an NSString*. So this points the address of that string. If you want to convert this into a number, you'll want to call -intValue on it.
That said, I wouldn't encode this data as a string. Encode it as a data object:
#interface ButtonInfo
#property (copy) NSString *name;
#property (assign) NSInteger index;
#end
(or name could be an enum if there are fixed set of them)
If you want to make this easier to read, add a -description method. Use the type system; it's there to help you. Don't try to encode a complicated type into a string.
Use below line of code :
NSLog(#"and %li", [newString intValue]);
Your approach is correct.
Hi i am beginner in Ios and in my project login page there is textfields validations(here i have two textfields they are medicaId,password)
my medicaid must allows only numbers and medicaId starts with 10 and ends with 99 if not then i want show alert Invalid medicaId
but according to my experience i could able to do only textfield allows numbers but i am not understand how to do that textfield(my medicaid) starts with 10 and ends with 99 please help me some one
my code:-
#import "ViewController.h"
#interface ViewController ()
#define ACCEPTABLE_CHARECTERS #"0123456789"
#end
#implementation ViewController
#synthesize textfield;
- (void)viewDidLoad {
[super viewDidLoad];
textfield.delegate = self;
}
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
if (textField==textfield)
{
NSCharacterSet *cs = [[NSCharacterSet characterSetWithCharactersInString:ACCEPTABLE_CHARECTERS] invertedSet];
NSString *filtered = [[string componentsSeparatedByCharactersInSet:cs] componentsJoinedByString:#""];
return [string isEqualToString:filtered];
}
return YES;
}
-(IBAction)CickMe:(id)sender{
if (success) {
NSLog(#"validations are perfect");
}else{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Alert" message:#"MedicaId must starts with 10 and ends with 99" delegate:self cancelButtonTitle:#"OK" otherButtonTitles:#"Cancel", nil];
[alert show];
}
}
My answer works perfectly.
- (IBAction)ClickMe:(id)sender
{
NSString *strID = textFieldUserID.text;
NSString *strLastTwoIndex = [strID substringFromIndex: [strID length] - 2];
NSLog(#"The strJoinedStr is - %#",strLastTwoIndex);
if([strID hasPrefix:#"10"] && [strLastTwoIndex isEqualToString:#"99"])
{
NSLog(#"Success");
}
else{
NSLog(#"Failure");
}
}
The console output is
Success
You can take string from text field and check using set operation that if it contains only number or not.
Then use the NSString function like hasPrefix and hasSuffix to check, if it has certain value at start or end.
-(void) validate
{
BOOL isSuccess = FALSE;
NSString *input = textField.text;
if(input.length > 4)
{
if([input hasPrefix:#"10"] && [input hasSuffix:#"99"])
isSuccess = TRUE;
}
}
In general these kind of constraints can easily be solved using regular expressions. They allow you to easily specify quite complex constraints on a given input string. (as long as you do not want to count). Take a look here for how to use regular expressions in Objective-C.
BUT you have a slightly different situation here that you have to deal with: the user is not going to input the entire string at once - he will input character after character. It is pretty much impossible to check during the user input wether or not what he is going to end up with might be a valid input. For example there will not be a leading 99 when the user types in the first few chars. You can certainly prevent him from typing in anything else other than numbers since they will ne never be a valid character anywhere in the entire input.
If you implement the entire validation inside shouldChangeCharactersInRange you are going to have a bad day:
Imagine the user starts typing
1 - does not start with 10 and does not end with 99 -> reject
10 - does not end with 99 -> reject
102 - does not end with 99 -> reject
1029 - does not end with 99 -> reject
10299 - approve
1299 - does no longer start with 10 -> reject
If you actually reject invalid input the user would never be able to get to a valid input since the starting point always will be invalid.
All you can do is perform a check and notify the user that the input is invalid - but you must not reject the input. (You can display an exclamation mark, change the font color, etc.)
As #Apurv wrote, in your "simple" situation you would probably not even need to use a regular expression but could use basic string operations. But the above statements regarding not rejecting the user input during the input remains true.
A slight variation of the strict statement above is that you can actually reject any non-number character since they will always create an invalid input.
Instead of dealing with hand-made methods you should really use Cocoa's core technologies.
A. Number Formatters
You should read the introduction to number formatters. Instances of NSNumberFormatter support a range with minimum and maximum values. Moreover, they transform strings to numbers and back.
B. Key-Value-Validation
The intended concept for value validation is key-value validation. You should alway implement this instead of custom-made methods. (I. e. you get the benefit, that technologies in Cocoa uses this methods, when doing its own validation.)
After allowing only numbers, you only have to filter out illegal values. In your case it would be:
-(BOOL)validateYourPropertyNameHere:(id *)ioValue error:(NSError * __autoreleasing *)outError {
// Do some checking, i. e. …
}
Typed in Safari.
It is a littlebit tricky, because you have three options:
The value is correct: Simply return YES.
The value is incorrect, but can be converted to a correct value (i. e. input is 103 and you want to convert it to 99): create a new object and assign the reference to ioValue, return YES.
The value is incorrect and you cannot or don't want to convert it to a correct value: return NO.
C. Using
You use your validation method from everywhere you deal with the take-over of the input. simply:
NSError *error;
if( [self validateYourPropertyNameHere:&userInput error:&error] == NO )
{
// Display error or whatever
}
else
{
// Use value
}
Don't hesitate to add comments, if you have more questions.
BTW:
#define ACCEPTABLE_CHARECTERS #"0123456789."
#define MAX_LENGTH 5
… is really no good style. But this is another Q. Maybe you should have a look at least at NSCharacterSet.
This question already has answers here:
Sort characters in NSString into alphabetical order
(4 answers)
Closed 8 years ago.
I have a label, a text field and a button. The user introduces a sequence of letters in the text field, e.g. "gcea", presses the button, and the label text becomes "aceg".
What i have so far in .h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
#property (weak, nonatomic) IBOutlet UILabel *label;
#property (weak, nonatomic) IBOutlet UITextField *random;
- (IBAction)ok:(id)sender;
#end
What i have so far in .m
- (IBAction)ok:(id)sender {
NSString *order = self.random.text;
NSInteger compare = order.length;
NSString *corect = #"abc";
// will insert all letters when it will actually work:)
BOOL count = YES;
for (int i=0;i<compare;i++)
{
if([corect characterAtIndex:i] == [order characterAtIndex:i])
{
//do stuff?;
}
}
self.label.text = [NSString stringWithFormat:#"%c", count];
}
#end
So what should I do next from here? My thought process is that I compare my "correct" string to what the user put in char by char and print the result in another string. But I have no idea how to actually write this, so can anyone please give me some pointers?
Also please don't use any predefined methods, I want to understand bools & for loops better first.
I'm brand new to programming.
I disagree with the other posters that your question was a duplicate of the linked post.
Several things:
First: Sorting is actually a very complex subject. I suggest you read the wiki article on sorting. Naive sorting algorithms like bubble sort are easy to write, but VERY inefficient. Their time to sort tends to go up with the square of the number of elements being sorted, which is bad news for sorting longer lists. Still, learning a naive sorting algorithm is a worthwhile exercise.
Second: NSString, and it's mutable subclass, NSMutableString, don't really lend themselves to manipulating a string character by character.
The suggestion of creating an array of single-character strings isn't bad as a learning exercise, or perhaps even sorting a C string.
You might want to start with a simpler problem like sorting a C array of numbers. Here is some sample code to do that:
//Create an array of mixed-up integers
int array[] = {73, 12, 135, 18, 200, 1, 416};
//an outer loop for indexing into the array starting at the first element and going to
//the next-to-last item.
for (int outer = 0; outer < sizeof(array)-1; outer++)
{
//An inner loop that starts one past the current outer loop,
//and goes to the end of the array
for (int inner = outer+1; inner< sizeof(array); inner++);
{
//If the items at the outer and inner loop indexes are out of order, swap them
if (array[outer] > array[inner])
{
int temp = array[outer];
array[outer] = array[inner];
array[inner] = temp;
}
}
}
The above code is a bad sort algorithm. For an array of n elements, it always does n^2 comparisons. However, it's fairly easy to understand what it does.
In standard computer science terminology, this is known as O(n squared) performance, or just n squared performance, which is bad news.
You could adapt the code above to sort characters in an NSString, but it would be kind of painful. As somebody else suggested, you'd have to break your string into a mutable array of NSNumbers that hold the value of each character in the string, then use code like the above to sort the array of numbers.
Test that sort algorithm on a string of 100 characters. It will seem fast. Then give it a string of 10,000 characters. It will take quite a while. That's because it will have to do 10,000 x 10,000, or 100 million comparisons.
Next look up a sort like quicksort or shell sort. Those are more work to figure out and implement, but much, much more efficient. If I remember correctly both of those sort algorithms typically have n * log(n) performance, which is MUCH better.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
This is for Xcode 5 and for iOS apps; I'm working with Objective-C code.
Okay so for example, if I put into the first text field "I was born in 1995." and when I click a convert button, I want it to say "I was conceived circa 1995." How can I go about doing that? The problem I'm having is being able to replace a word with another word.
Like, how do I return whats in the text field to be replace the possible words into whatever the person types in? Sort of like a translator app, the way it replaced words.
My question concerns that if the user were to type anything into the text field, then it would rephrase it for him with words that have synonyms to be other words.
Yes, it is about replacing substrings, but it will replace whatever the user types into it.
I understand that stringByReplacingOccurrencesOfString:withString: makes sense, but what would go after that to apply to whatever the user typed in?
Basically, let's say a translator app. If I type in: "I am very smart." it would rephrase to: "I am very intellectual." It has to deal with whatever the user types in.
If the string is in NSString, you can use the stringByReplacingOccurrencesOfString:withString: method.
NSString *str = #"I was born in 1995.";
str = [str stringByReplacingOccurrencesOfString:#"born in" withString:#"conceived circa"];
Not sure though if this is what you mean.
Given a word, you want to find words with similar meaning. You will need a lot of data - arrays of words grouped by meaning. A given word may appear in several of these arrays depending on context (one reason why machine interpretation of language is difficult...).
The easy way to separate the string into words is to use componentsSeparatedByString: with a string of #" ". After that you need to identify which strings you want to try and replace. Whether or not they return anything useful using the dictionary described below is one way to decide.
A specific word can be used as a key into a dictionary returning an array of arrays. Let's say the word is "iron". When you use that as a key in your master dictionary it returns an array containing three arrays. In one are all the words (as NSStrings) that mean "elemental iron", in another are all the words that mean "smooth clothes with a hot tool" such as "press" or "smooth", in another are tool-like uses such as "shooting iron", "branding iron" etc.
The hardest thing you have to do is identify the context and choose the right array, or else you end up generating nonsense.
Once you have identified context you can choose any other word from the selected array, substitute it in the sentence, and then process other words you want to substitute.
To separate a string such as
NSString *string = #"I am very smart."
you would use
NSArray *words = [string componentsSeparatedByString:#" "];
you can iterate over the words with
for(NSString *word in words) {
// do something with NSString *word here
}
Here's a quick look at building the master dictionary - it hasn't been run but I'm sure someone will spot if there's a mistake...
// NSArray *arrayOfArraysOfSimilarWords; <- populated elsewhere, as shown below
// array
// |
// - "cat", "feline", "pussycat", "gato"
// - "shoe", "pump", "clog", "trainer"
NSMutableDictionary *masterDictionary = [NSMutableDictionary dictionary];
for(NSArray *wordArray in arrayOfArraysOfSimilarWords) {
for(NSString *word in wordArray) {
NSArray *arrayOfWordArrays = masterDictionary[word];
if(arrayOfWordArrays == nil) {
masterDictionary[word] = #[wordArray];
} else {
// entry exists
NSSet *wordArraySet = [NSSet setWithArray:arrayOfWordArrays];
if([wordArraySet containsObject:wordArray]) {
// this word array is already returned as a result for this word
continue;
}
// there is no entry for this word array yet - add an array containing the current word array
NSMutableArray *newArrayOfWordArrays = [NSMutableArray arrayWithArray:arrayOfWordArrays];
[newArrayOfWordArrays addObject:wordArray];
masterDictionary[word] = newArrayOfWordArrays;
}
}
}
If you're trying to do in place replacement of strings while the user types you will need probably to use the UITextFieldDelegate method:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
This is called on every character insertion (or text paste) in a UITextField.
Pseudo code (because I'm writing this off the top of my head):
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
NSMutableString *proposedText = [textField.text mutableCopy];
[proposedText replaceCharactersInRange:range withString:string];
if (proposedText contains word I want to replace)
{
replace word in proposedText
textField.text = proposedText;
textField.selectedTextRange = new selection
return NO;
}
return YES;
}
Hope this helps.
Please bear with me as I'm very new to the world of iOS and Objective-C. I've read Apple's Obj-C primer, as well as a few free ones provided on the web.
On a button press, I'm trying to simply take the text of a label and concatenate it with a string. My mindset is still very much in Android/Java and how simple it could be, but I'm having trouble here. Nonetheless here is my code:
- (IBAction)myButton:(UIButton *)sender {
self.myLabel.text = [self.myLabel.text stringByAppendingString:#"obj-c is hard =/"];
}
It seems pretty standard, but I can imagine myself doing this often so I want to make sure this is correct or what other ways are there to do this?
Yes this is correct way. And if you want to use another method then use this one
self.myLabel.text = [NSString stringWithFormat:#"%# obj-c is hard =/",self.myLabel.text];
It is the standard way to join string.As ios updated syntaxes to make it easy like NSArray and NSDictiornary delaration but for concatenation it has not declared any shortcut way.
Have a look at this
OR
you can use a trick to simplify concatenation of string.Pass a parameter to macro and use following joining literal syntax.
#define STRING(text) #""text""
#implementation SPTViewController
- (void)viewDidLoad
{
NSString *joinedFromLiterals =STRING(#"Congratulations!, ") #"I " #"really " #"enjoy " #"carpenting!";
NSLog(#"joined string %#",joinedFromLiterals);
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
output is ---------
joined string Congratulations!, I really enjoy carpenting!
Yes, this is correct, but there is a gotcha. If you haven't previously set the value of self.myLabel.text, it will be nil by default. Then the result of calling any method (like [self.myLabel.text stringByAppendingString:#"obj-c is hard =/"]) will also be nil, so myLabel will still have empty text. The way Objective-C handlesnil values is different than handling null in Java.
So to be safe, initialize label's text first:
self.myLabel.text = #"";
You are doing it right. Sure Objective-C is a bit more verbose than C# or Java or even Visual Basic .net (as I used to work on all those languages) but don't be bugged by those long method names. Although some #defines can be very helpful like (rewritten as C inline function):
static inline __attribute__((always_inline))
__attribute__((format(NSStirng, 1, 2)) NSString *SKSTR(NSString *fmt, ...)
{
va_list args;
va_start(args, fmt);
NSString *string = [[NSString alloc] initWithFormat:fmt arguments:args];
va_end(args);
#if !__has_feature(objc_arc)
[string autorelease];
#endif
return string;
}
Hope the __attribute__s and #ifs does not confuse you - you can safely ignore them.
To use:
self.label.text = SKSTR(#"%#, ugh!", self.label.text); // just like NSLog or snprintf :)