Hi i'm trying to get to NSStrings to equal each other in length for a project of mine but i'm seem to be having trouble. I got two string
NSString *word1=#"123456";
NSString *word2=#"123";
I hard coded them to be different lengths for other testing.I'm trying to append 0s at the from of word to so it'll look like #"000123" and i tried this method to append the string but instead it builds up ram and if i leave the program running long enough my system crashes..any help on how to fix this? is there a different method to doing this?
while ([word1 length]>[word2 length]){
[word2 stringByAppendingString:#"0"];
}
while ([word1 length]<[word2 length]){
[word1 stringByAppendingString:#"0"];
}
You are not changing the strings. NSString objects are immutable, you either have to assign the result:
word2 = [word2 stringByAppendingString:#"0"];
or use NSMutableString and appendString:
[word2 appendString:#"0"];
You also have to reverse your logic, as "append" means "add to the end".
append |əˈpɛnd|
verb [ with obj. ]
add (something) to the end of a written document: the results of the survey are appended to this chapter.
You need to change your code to this
while ([word1 length]>[word2 length]){
word2 = [word2 stringByAppendingString:#"0"];
}
while ([word1 length]<[word2 length]){
word1 = [word1 stringByAppendingString:#"0"];
}
I think the reason for the memory increase and app crash is because you are having an infinite loop in your old code. Try putting NSLog into the while loop in your old code and see what is the output. The code I suggested should not have such problem.
Related
My mac version is 10.13.4 with xcode version 9.4.1
I'm trying to use NSSpellChecker with Korean language. But regardless of whether the word I check is misspelled or not, the Range returned is {2^63 - 1, 0}
Based on quick experiments with english, that Range is returned when there are no misspelled words OR if the input word language doesn't match current spell checker's language.
This is what I'm doing:
NSSpellChecker *checker = [NSSpellChecker sharedSpellChecker];
NSString *sampleWord = #"마직막";
NSRange range = [checker checkSpellingOfString:sampleWord, startingAt: 0];
NSLog(#"range: %#", NSStringFromRange(range));
that sampleWord is misspelled, but I'm getting
range: {9223372036854775807, 0}
as the output.
Could someone provide any insight on what's happening?
Edit1: When I throw correct english words at it, NSSpellChecker indicates spelling error, which is correct. I gave an english word to korean environment. So I guess NSSpellChecker itself is working correctly, but there is something I missed regarding setup kind of..?
Here is code I used, based on your code and comments.
// insert code here...
NSSpellChecker *checker = [NSSpellChecker sharedSpellChecker];
// NSLog ( #"Available %#", checker.availableLanguages );
NSLog ( #"Korean %#", [checker.availableLanguages containsObject:#"ko"] ? #"YES" : #"NO" ); // Prints YES
[checker setAutomaticallyIdentifiesLanguages:NO]; // Seems to have NO impact
NSLog ( #"KO %#", [checker setLanguage:#"ko"] ? #"YES" : #"NO" ); // Prints YES
// NSString * sampleWord = #"마직막 마직막 마직막 마직막 마직막"; // makes no difference
NSString * sampleWord = #"마직막"; // makes no difference
// NSString * sampleWord = #"마직막 ddd sss aaa"; // consistently prints { 4, 3 }
// NSString * sampleWord = #"안녕하세요 햇살 가득한 남아프리카에서 왔습니다. 마직막 안녕하세요 햇살 가득한 남아프리카에서 왔습니다."; // all fine for this one also
// NSString * sampleWord = #"안녕하세요 햇살 가녕하세득한 남녕하세아프리카에서 왔습니다. 마직막 안녕하세요 햇녕하세살 가득한 남아프리카에서 왔습니다."; // here I finally start to see some result { 45, 5 }
NSRange range = [checker checkSpellingOfString:sampleWord
startingAt:0];
NSLog(#"range: %#", NSStringFromRange(range)); // Consistently prints { NSNotFound, 0 }
NSInteger wc;
// Since you force the language I think this
// is better way of checking
range = [checker checkSpellingOfString:sampleWord
startingAt:0
language:#"ko"
wrap:NO
inSpellDocumentWithTag:0
wordCount:& wc];
NSLog(#"spelling range: %# wc %lu", NSStringFromRange(range), wc); // Consistently prints { NSNotFound, 0 } wc 1
range = [checker checkGrammarOfString:sampleWord
startingAt:0
language:#"ko"
wrap:NO
inSpellDocumentWithTag:0
details:nil];
NSLog(#"grammer range: %# wc %lu", NSStringFromRange(range), wc); // Consistently prints { NSNotFound, 0 } wc 1
The word you are testing with 마직막 appears to be valid and passes consistently - even in the grammar test.
If I create some kind of a sentence and mess it up by randomly pasting in letters then I start getting some sensible (and consistent) feedback from the spell checker. See the code for more info.
Mostly I think you should use, as shown in the code, the message that allows you to specify the language rather than the one that does not since you are forcing the language. But I do not see inconsistency here. If I paste the word into Notes it also does not highlight it, although my intentionally erroneous string does light up there as well.
EDIT
I've played with your code a bit. Note that readline will append the newline so I changed the code by trimming all white space and newlines from theWord as below.
NSString *sampleWord = [[NSString stringWithCString:theWord encoding:NSUTF8StringEncoding] stringByTrimmingCharactersInSet:NSCharacterSet.whitespaceAndNewlineCharacterSet];
Initially I got the discrepancy you mention but just as I got excited it disappeared. So yes, it seems inconsistent. I am not sure if the spell checker got smarter or if the console got better at dealing with the input.
The basic problem, I believe, is that getline reads chars. So I also tried e.g.
NSString *sampleWord = [[[NSString alloc] initWithBytesNoCopy:theWord
length:len_read
encoding:NSUTF8StringEncoding
freeWhenDone:YES] stringByTrimmingCharactersInSet:NSCharacterSet.whitespaceAndNewlineCharacterSet];
but got the same result. Here I also tried
NSASCIIStringEncoding
and
NSUTF16StringEncoding
but only
NSUTF8StringEncoding
worked correctly, so it seems the console returns UTF8 strings. At least for me, I suspect this will be different based on the locale and other settings.
Discrepancy
So what about that. Yesterday when I ran my code, for the very first time, I think it produced a spelling error. Never again. I ran it a lot but never again and I am not even sure it really did produce that error anymore. Same today. I ran your code and the first time it marked the word as an error, but never again. By now, after running it again many times, I am starting to wonder if I was not mistaken as I simply can not generate it again.
Maybe the spell checker takes a while to initialise and this gives rise to the discrepancy. I could not find anything in the manual that points to this. Maybe the console gets smart as I enter Hangul and this is why it generates two separate outputs. Maybe the clipboard sees I am copy and pasting Hangul and changes something somewhere.
The strange thing though is that I repeated the whole thing on my MacBook as well, hoping to get the failure / misspelt word the first time again and this time copying the log out. But there it just worked from the first time.
Maybe run your code a few times and see if it stabilises after a while. Here it seems that (maybe) the first time it marks the word as misspelt but never again, so I am as perplexed as you are at present.
Follow up
Note that I am unable to get the spellchecker to mark the word as misspelt. I also tried the other words you gave and later even some gibberish but the spell checker never flagged anything as incorrect.
Then I tried on my Mac again and this time everything I tried was marked (correctly) as incorrect. So the result is not consistent between my Mac and Macbook, although, where it works, it seems that "마직막" is spelt correctly according to Apple.
I can not explain this but suspect it has to do with language and locale setting differences between the two machines, even though the code is the same and there are no differences I am aware of. On both machines the output is the same, notably it outputs YES when I initialise the Korean dictionary.
This is the code I'm using right now, where "마직막" is failing.
while(true) {
char *theWord = NULL;
size_t len = 0;
printf("ENTER A WORD\n");
size_t len_read = getline(&theWord, &len, stdin);
printf("%s\n", theWord);
NSString *sampleWord = [NSString stringWithCString:theWord encoding:NSUTF8StringEncoding];
NSInteger wc;
NSRange range = [checker checkSpellingOfString:sampleWord startingAt:0 language:#"ko" wrap:NO inSpellDocumentWithTag:0 wordCount:&wc];
if (range.location == NSNotFound) {
printf("Correct Spelling\n");
} else {
printf("Bad Spelling. Incorrect Spelling at\n");
NSLog(#"The range: %#", NSStringFromRange(range));
}
fflush(stdin);
free(theWord);
}
And if I input "마직막", this is what I'm getting.
ENTER A WORD
마직막
ㅁㅏㅈㅣㄱㅁㅏㄱ
Bad Spelling. Incorrect Spelling at
2020-11-27 10:39:23.916315+0900 spellCheckTest[6410:124279] The range: {0, 8}
So we're getting different results using the same input. Could this be because of how I'm accepting input from console??
So I'm reading the most recent tweet from a twitter bot and assigning it to a string, but sometimes it tweets directly to users. Here's an example of what that might look like.
NSString tweet = #("#user hey heres my message: BLah blah with symbols!");
//part I want to keep is: " BLah blah with symbols!"
//or it could end up being
NSString tweet = #("#otheruser my msg is: Wow heres some more blah: and a second colon");
//part I want to keep is: " Wow heres some more blah: and a second colon"
I want to always remove the first part that talks to the user, while keeping the message on the end. There are too many different messages to use "stringByReplacingOccurrencesOfString"
I don't want to use "exlude-replies" from the twitter API because this bot is very popular and that would require fetching up to 100 since "count" applies before
any idea how I could do this? I think it has something to do with regular expressions, but I haven't ever used them before or been able to get one working how I want. I would really appreciate the help from anyone whos comfortable with regex
edit: also if a regex won't work for this case, id accept an explanation of the limitation preventing that :)
The easiest solution that I can think of is to create an NSMutable array, by using the NSString function componentsSeparatedBy:#":", and simply remove the first element.
NSMutableArray *tweetArray = [[NSMutableArray alloc] initWithArray: [tweet componentsSeparatedByString:#":"]];
[tweetArray removeObjectAtIndex:0];
Your issue with a colon appearing at random afterwards can be fixed by joining the pieces back together again.
tweet = [tweetArray componentsJoinedByString:#":"];
Edit: Fix an error pointed out by user 'maddy'
You'll have to stick this code in an if statement so that it does not execute in tweets that have a colon normally. You can use the fact that it always begins with #user however.
if ([tweet characterAtIndex:0] == '#' && [tweet characterAtIndex:1] != ' '){
NSMutableArray *tweetArray = [[NSMutableArray alloc] initWithArray: [tweet componentsSeparatedByString:#":"]];
[tweetArray removeObjectAtIndex:0];
tweet = [tweetArray componentsJoinedByString:#":"];
}
You can also use this.
NSString *myString = #"#username is me: by using this as sample text";
NSRange range = [myString rangeOfString:#":"];
NSString *newString= [myString substringFromIndex:range.location];
NSLog(#"New String is : %#", newString);
So I have this function:
void step (NSTextField *input, char move, int position, NSTextField *label) {
int delta = input.intValue;
for (int i = 0; i < delta; i++) {
pclose(popen("echo move > /dev/tty.usbmodem621", "r"));
position = position +1;
[NSThread sleepForTimeInterval:t1];
NSString *printPosition = [NSString stringWithFormat: #"%i", position];
label.stringValue = printPosition;
}
}
And in the line:
pclose(popen("echo move > /dev/tty.usbmodem621", "r"));
Move should be the variable character that I declared at the beginning. But I can't seem to find out how to do that. Could somebody enlighten me?
Also there is an other thing I don't understand. If for example my input is 20 the and i run this script it counts 20 like it supposed to. However when I input a new value it doesn't ad that one up to the 20 that's already there like I hoped it would. Instead it just displays the new value. Any ideas?
Thanks
To generate string with move:
NSString *str = [NSString stringWithFormat:#"echo %c > /dev/tty.usbmodem621", move];
About not adding more characters, it is hard to say with this example. I can see that your position always starts from 0 because it is incoming parameter but not retuned back. Maybe that's the issue?
This is...not how I would do this. You don’t need to open a pipe or do an echo or any of that stuff to write to a device.
Look into doing something like [NSFileHandle fileHandleForWritingAtPath:#"/dev/tty.usbmodem621”], and then writing to it with writeData:
You can get an NSData from an NSString by using -dataUsingEncoding:, probably with the ASCII encoding.
Yikes. Ok - first problem:
Move should be the variable character that I declared at the beginning
No. popen() executes shell commands and there's no way that it can bind to your move variable. What you need to do is compose a shell command with with move character in it. Something like this
char cmd[] = "echo # > /dev/tty.usbmodem621";
cmd[5] = move;
pclose(popen(cmd,"r"));
Which brings me to the second problem: constructing shell commands from external data and then blindly executing them creates an attack vector called "shell injection" which is quite a common way to hack into systems.
As another poster has already indicated, you don't need popen() to do this so if I were you I'd avoid and never compose shell commands unless you really have to.
I wan't to "know" how to put a string at a location in another string. I already know because I figured out another way to do this. But I wan't to know the real way, does it even exist?
I'm also asking this question for future questions on how to put this string at a location in another string the "false" way (in case it can't be done the real way)
What I mean about putting a (sub)string at a location of string is for example to put
this string:#"Hello" at location:5 inString:#"123456789"
I want the results to be:#"12345Hello6789"
Can this be done the real way? something like this fake code:
[str stringByPuttingString:#"s" atLocation:5];//this code does not exist
I figured out other ways to get this done, can we get it to shorter code?
-(NSString *)putString:(NSString *)str atLocation:(int)location ofString:(NSString *)mainString {
NSRange range = NSMakeRange(location, 0);
return [mainString stringByReplacingCharactersInRange:range withString:str];
}
and
-(NSString *)putString:(NSString *)str atLocation:(int)location ofString:(NSString *)mainString {
NSString *first = [mainString substringToIndex:location];
NSString *last = [mainString substringFromIndex:location];
return [NSString stringWithFormat:#"%#%#%#", first, str, last];
}
The first one feels best, any other ideas or real ideas?
Jonathan,
in future cases of this "problem".
Why not just use an NSMutableString?
NSMutableString *string = [NSMutableString stringWithString:#"123456789"];
[string insertString:#"Hello" atIndex:5];
NSLog(#"%#", string);
Outputs:
12345Hello6789
You can use NSMutableString to accomplish this task. Specifically, see the reference to the insertString:atIndex: method which will do exactly what you want, i.e. insert a string into another string at a specified location. API LINK
you can implement this by using NSMutableString method insertString:atIndex:
Inserts into the receiver the characters of a given string at a given location.
- (void)insertString:(NSString *)aString atIndex:(NSUInteger)anIndex
Parameters
aString
The string to insert into the receiver. aString must not be nil.
anIndex
The location at which aString is inserted. The location must not exceed the bounds of the receiver.
Taken from apple developer classes ref
I have the following C array of NSString *:
static NSString *const OrderByValueNames[] = {#"None",#"Added",#"Views",#"Rating",#"ABC",#"Meta"};
Now, I want to check the length of this array at runtime so I wrote the following method:
NSInteger LengthOfArray(NSString *const array[])
{
NSInteger length = 0;
// For Loop Without a body!
for (length = 0; array[length] != nil; length++);
return length;
}
Now, when I run this code at debug configuration, everything is fine and the function returns the right result.
BUT as soon as I switch to release configuration and run it again, the program freezes at the for loop. After 10 seconds of the loop being executed, iOS kills the app for not responding. Weird.
Now, if I add body to the loop, like that:
for (length = 0; array[length] != nil; length++)
{
NSLog(#"%d",length);
}
Then it's working fine even in release mode.
Giving the loop an empty body, like that:
for (length = 0; array[length] != nil; length++){}
Still freezes in release mode.
My guess is that there is a compiler optimization when running in release mode, but what exactly?!
Any ideas?
C-style arrays are not nil-terminated by default. If you want to check the length this way, you need to add the terminator yourself.
static NSString *const OrderByValueNames[] =
{#"None",#"Added",#"Views",#"Rating",#"ABC",#"Meta",nil};
A much better way to find the length is simply this:
length = sizeof(OrderByValueNames) / sizeof(OrderByValueNames[0]);
(Note that this trick doesn't work if you pass the array into a function, since it then degenerates into a pointer.)
Your OrderByValueNames array doesn't contain a nil element. No wonder you can't find one! Walking off the end of the array like that will result in undefined behaviour. If you want to mark the end of the array with nil, you'll have to add it manually.
By the way, if you'd like to know the length of a fixed size C array, you can do this:
length = sizeof(OrderByValueNames)/sizeof(OrderByValueNames[0]);
This doesn't work for function parameters, though, as those are just pointers!