Objective-C - Translate string to different characters using a dictionary - ios

I have an iOS program that takes a string from the user, splits the string up by character, and then uses each character as a key to grab a seperate (morse code) character from a dictionary. I'm having issues regarding the char*s and strings, and I am receiving errors having to do with improper types and not finding the key in the array. Thoughts please? Thanks in advance.
Here is the code:
//
// ViewController.m
// MorseCodeTranslator
//
// Created by Mitch on 4/30/14.
// Copyright (c) 2014 Mitch . All rights reserved.
//
#import "ViewController.h"
#interface ViewController ()
#property (weak, nonatomic) IBOutlet UITextField *userInput;
#property (weak, nonatomic) IBOutlet UILabel *outputField;
- (IBAction)translateUserString:(UIButton *)sender;
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
- (IBAction)translateUserString:(UIButton *)sender {
BOOL stringPresent = (self.userInput.text.length > 0);
if (stringPresent) {
NSDictionary *morseCharacterKey = #{
#"A" : #".-",
#"B" : #"-...",
#"C" : #"-.-.",
#"D" : #"-..",
#"E" : #".",
#"F" : #"..-.",
#"G" : #"--.",
#"H" : #"....",
#"I" : #"..",
#"J" : #".---",
#"K" : #"-.-",
#"L" : #".-..",
#"M" : #"--",
#"N" : #"-.",
#"O" : #"---",
#"P" : #".--.",
#"Q" : #"--.-",
#"R" : #".-.",
#"S" : #"...",
#"T" : #"-",
#"U" : #"..-",
#"V" : #"...-",
#"W" : #".--",
#"X" : #"-..-",
#"Y" : #"-.--",
#"Z" : #"--..",
#"1" : #".----",
#"2" : #"..---",
#"3" : #"...--",
#"4" : #"....-",
#"5" : #".....",
#"6" : #"-....",
#"7" : #"--...",
#"8" : #"---..",
#"9" : #"----.",
#"0" : #"-----",
#" " : #"/",
#"," : #"--..--",
#"." : #".-.-.-",
#"?" : #"..--..",
#"\'" : #".----.",
#"!" : #"-.-.--",
#"/" : #"-..-.",
#"(" : #"-.--.",
#")" : #"-.--.-",
#"&" : #".-...",
#":" : #"---...",
#";" : #"-.-.-.",
#"=" : #"-...-",
#"+" : #".-.-.",
#"-" : #"-....-",
#"_" : #"..--.-",
#"\"" : #".-..-.",
#"$" : #"...-..-",
#"#" : #".--.-."
};
NSString *userString = self.userInput.text;
NSString *outputString;
for (int i = 0; userString.length > i; i++){
char userCharacter = [userString characterAtIndex:i];
char morseCharacter = [morseCharacterKey objectForKey:morseCharacterKey[userCharacter]];
outputString stringByAppendingString:[morseCharacter];
self.outputField.text = outputString;
}
}
}
#end

Your code should use NSString:
for (int i = 0; userString.length > i; i++) {
NSString *userCharacter = [userString substringWithRange:NSMakeRange(i, 1)];
NSString *morseCharacter = morseCharacterKey[userCharacter];
outputString = [outputString stringByAppendingString:morseCharacter];
NSLog(outputString);
}
}

So:
#"A"
Is an NSString literal. So your dictionary keys:
NSDictionary *morseCharacterKey = #{
#"A" : #".-",
...
Are NSString*s. Which is fine, because keys are required to be objects.
You're getting the character as a char, which is not an object, and even if it was it isn't the same object as you used for your keys.
Instead what you want to do is something like this:
NSRange range;
range.location = i;
range.length = 1;
NSString* userCharacter = [userString substringWithRange:range];
And use userCharacter as your key. Note that your values are also NSString*s, so you should store the result of your dictionary lookup in an NSString as well.

You shouldn't be working with char. Try this:
NSString *userString = self.userInput.text;
NSMutableString *outputString = [NSMutableString string];
for (NSUInteger i = 0; i < userString.length; i++) {
NSString *letter = [userString substringWithRange:NSMakeRange(i, 1)];
NSString *morse = morseCharacterKey[letter];
[outputString appendingString:morse];
}
self.outputField.text = outputString;

Block based enumeration would clean this up a little bit. Also a NSMutableString would be better then using stringByAppendingString. Also since I use a mutableString we don't have to use the __block specify in order to append to it like we would if stringByAppending string was used.
NSString *string = #"...";
NSMutableString *output = [[NSMutableString alloc] init];
[string enumerateSubstringsInRange:NSMakeRange(0, string.length) options:NSStringEnumerationByComposedCharacterSequences usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
NSString *value = morseCharacterKey[substring];
[output appendString:value];
}];

Related

Transform punctuations form half width to full width

I have a sentence below:
我今天去买菜,买了一个西瓜,花了1.2元,买了一个土豆,花了3.78元。还买了一个无花果,花了45.89,怎么办呢?好贵呀!贵的我不知道再买什么了。
The punctuations in it are half width. How to change them to fullwidth, like the following:
我今天去买菜,买了一个西瓜,花了1.2元,买了一个土豆,花了3.78元。还买了一个无花果,花了45.89,怎么办呢?好贵呀!贵的我不知道再买什么了。
Some punctuations to consider (not exhaustive):
, to ,
? to ?
! to !
"" to “”
; to ;
First, define the CharacterSet from which you want to transform your characters. So if you want only punctuation, the set could be CharacterSet.punctuationCharacters or CharacterSet.alphanumerics.inverted.
Then map each character from this set to its HalfwidthFullwidth transformation.
Swift 3 and 4
extension String {
func transformingHalfwidthFullwidth(from aSet: CharacterSet) -> String {
return String(characters.map {
if String($0).rangeOfCharacter(from: aSet) != nil {
let string = NSMutableString(string: String($0))
CFStringTransform(string, nil, kCFStringTransformFullwidthHalfwidth, true)
return String(string).characters.first!
} else {
return $0
}
})
}
}
Usage
let string = ",?!\"\";abc012図書館 助け 足場が痛い 多くの涙"
let result = string.transformingHalfwidthFullwidth(from: CharacterSet.alphanumerics.inverted)
// it prints: ,?!"";abc012図書館 助け 足場が痛い 多くの涙
print(result)
Objective-C
#implementation NSString (HalfwidthFullwidth)
- (NSString *)transformingHalfwidthFullwidth:(nonnull NSCharacterSet *)aSet {
NSUInteger len = self.length;
unichar buffer[len + 1];
[self getCharacters:buffer range:NSMakeRange(0, len)];
for (int i = 0; i < len; i++) {
unichar c = buffer[i];
NSMutableString *s = [[NSMutableString alloc] initWithCharacters:&c length:1];
NSRange r = [s rangeOfCharacterFromSet:aSet];
if (r.location != NSNotFound) {
CFStringTransform((CFMutableStringRef)s, nil, kCFStringTransformFullwidthHalfwidth, true);
[s getCharacters:buffer + i range:NSMakeRange(0, 1)];
}
}
return [NSString stringWithCharacters:buffer length:len];
}
#end
Usage
NSString *string = #",?!\"\";abc012図書館 助け 足場が痛い 多くの涙";
NSString *result = [string transformingHalfwidthFullwidth:NSCharacterSet.alphanumericCharacterSet.invertedSet];
// it prints: ,?!"";abc012図書館 助け 足場が痛い 多くの涙
NSLog(result);
you can use CFStringTransform like :
Objective C :
NSString *string = #" ? \"\"!我今天去买菜,买了一个西瓜,花了1.2元,买了一个土豆,花了3.78元。还买了一个无花果,花了45.89,怎么办呢?好贵呀!贵的我不知道再买什么了";
NSMutableString *convertedString = [string mutableCopy];
CFStringTransform((CFMutableStringRef)convertedString, NULL, kCFStringTransformFullwidthHalfwidth, true);
NSLog(#"%#",convertedString);
Swift 3.0 :
let string = NSMutableString( string: " ? \"\"!我今天去买菜,买了一个西瓜,花了1.2元,买了一个土豆,花了3.78元。还买了一个无花果,花了45.89,怎么办呢?好贵呀!贵的我不知道再买什么了" )
CFStringTransform( string, nil, kCFStringTransformFullwidthHalfwidth, true )
print(string)

Mantle 2.0 cannot parse JSON for the notation in array nested

The following codes parsing JSON don't work any more for me after I update Mantle to 2.0. They can work fine on an older Mantle version( I don't remember the correct version number. What I know is I downloaded it in Nov of 2013.)
Here is the JSON content:
{
date = "2015-05-21";
error = 0;
results = (
{
currentCity = "beijing";
index = (
{
des = "desc1";
tipt = "tipt1";
title = "title1";
zs = "zs1";
},
{
des = "desc2";
tipt = "tipt2";
title = "title2";
zs = "zs2";
},
{
des = "desc3";
tipt = "tipt3";
title = "title3";
zs = "zs3";
}
);
}
);
status = success;
}
The Model I defined:
// .h
#import "MTLModel.h"
#import "Mantle.h"
#interface BaiduWeatherResults : MTLModel<MTLJSONSerializing>
#property (nonatomic, strong) NSNumber *error;
#property (nonatomic, strong) NSString *status;
#property (nonatomic, strong) NSString *date;
#property (nonatomic, strong) NSString *currentCity;
#end
// .m
#import "BaiduWeatherResults.h"
#implementation BaiduWeatherResults
+ (NSDictionary *)JSONKeyPathsByPropertyKey
{
return #{
#"error" : #"error",
#"status" : #"status",
#"date" : #"date",
#"currentCity" : #"results.currentCity",
};
}
+ (NSValueTransformer *) currentCityJSONTransformer
{
return [MTLValueTransformer reversibleTransformerWithForwardBlock:^(NSArray *values) {
return [values firstObject];
} reverseBlock:^(NSString *str) {
return #[str];
}];
}
Parse JSON to Model
id results =[MTLJSONAdapter modelOfClass:[BaiduWeatherResults class]
fromJSONDictionary:responseObject
error:nil];
NSLog(#"results:%#", results);
My Question:
The codes can work on an older Mantle. On the Mantle 2.0, the parse failed once I added #"currentCity" : #"results.currentCity" into the dictionary returned by JSONKeyPathsByPropertyKey . Anyone know what I missed for the parsing?
BTW, the currentCityJSONTransformer did call when the parse began. But the transformer is never used, because the line "return [values firstObject];" is never executed.
Thanks in advance.
Try this -
+ (NSDictionary *)JSONKeyPathsByPropertyKey
{
return #{
#"error" : #"error",
#"status" : #"status",
#"date" : #"date",
#"currentCity" : #"results",
};
}
+ (NSValueTransformer *) currentCityJSONTransformer
{
return [MTLValueTransformer reversibleTransformerWithForwardBlock:^(NSArray *values) {
NSDictionary *cityInfo = [values firstObject];
return cityInfo[#"currentCity"];
} reverseBlock:^(NSString *str) {
return #[#{#"currentCity" : str}];
}];
}
Since results is an array of dictionaries, you can't access currentCity via dot syntax in JSONKeyPathsByPropertyKey. Instead the currentCityJSONTransformer finds the first dictionary in the results array and returns its value for currentCity. You might want to add type-checking and define the #"currentCity" key in a single place.

How to separate the sentence into words?

split the sentence into words with out using "componentsSeparatedByString:"
my word is "This is a well known simple"
I wrote like this separtedWord=[noteTextView.text componentsSeparatedByString: #" "];
but I want with out using componentsSeparatedByString.please help me
I have wrote following logic. Created two properties like this :
#property(nonatomic,strong) NSMutableArray *strings;
#property(nonatomic,strong) NSMutableString *tempString;
Wrote business logic like this :
NSString *sampleString = #"This is a well known simple";
self.tempString = [[NSMutableString alloc] init];
self.strings = [[NSMutableArray alloc] init];
for( int i = 0; i < sampleString.length; i++ )
{
unichar currentChar = [sampleString characterAtIndex:i];
NSString *character = [NSString stringWithCharacters:&currentChar length:1];
if( currentChar != ' ' )
{
[self.tempString appendString:character];
if( i == sampleString.length - 1 )
{
[self addString:self.tempString];
}
}
else
{
[self addString:self.tempString];
[self.tempString setString:#""];
}
}
NSLog(#"Array Of String = %#",self.strings);
- (void)addString:(NSString *)string
{
[self.strings addObject:[NSString stringWithString:string]];
}
2014-07-24 15:23:22.306 ViemoPlayer[1834:70b] Array Of String = (
This,
is,
a,
well,
known,
simple
)
Hope this helps.
Convert the NSString into a char array.
Loop through the array and an if statement inside, and keep appending the charecters inside the charArray into a local NSMutableString using
for(int i =0;i<[myCharArray count];i++){
NSMutableString *teststring;
[teststring appendString:[myCharArray objectAtIndex : i]];
if([myCharArray objectAtIndex] == " "){
NSLog(teststring);
teststring = #""; //emptying the testString when we get a space
}
}
That should do it

Occurance of character after specific index

Is there any way to achieve what JAVA function int indexOf(int ch, int fromIndex) do.
Let me explain it:
NSString *steSample = #"This is sample test string";
Now i want to get the index of i but after 2nd index. How can I achieve this.
Thanks in advance
the regex way is too complicated for me :)
can't we just trim it and then look for it?
that'd be 3 lines...
wrapped in a category:
#import <Foundation/Foundation.h>
#interface NSString (Extend)
-(NSUInteger)indexOfSubstring:(NSString*)needle afterIndex:(NSUInteger)index;
#end
#implementation NSString (Extend)
-(NSUInteger)indexOfSubstring:(NSString*)needle afterIndex:(NSUInteger)index {
id str = [self substringFromIndex:index];
NSUInteger i = [str rangeOfString:needle].location;
return i==NSNotFound ? i : i+index;
}
#end
Demo usage:
int main(int argc, char *argv[]) {
#autoreleasepool {
id str = #"#asd#asd";
NSUInteger index = [str indexOfSubstring:#"#" afterIndex:2];
NSLog(#"index of # is: %d", index);
}
}
I'd do something like this:
NSString *_sample = #"This is sample test string";
NSError *_error;
NSRegularExpression *_regExp = [NSRegularExpression regularExpressionWithPattern:#"i" options:NSRegularExpressionCaseInsensitive error:&_error];
NSArray *_matches = [_regExp matchesInString:_sample options:NSMatchingReportCompletion range:NSMakeRange(0, _sample.length)];
[_matches enumerateObjectsUsingBlock:^(NSTextCheckingResult * result, NSUInteger idx, BOOL *stop) {
if (idx == 0) {
NSLog(#"ignoring first occurance...");
} else {
NSLog(#"occurance's index : %d, character's index in string : %d", idx, result.range.location); // that line is simplified for your problem
}
}];
NOTE: you can rearrange the actual if statement, it currently 'skips' the first occurance and prints the rest – but it can be customised for your further wish.
my console shows something like this:
ignoring first occurance...
occurance's index : 1, character's index in string : 5
occurance's index : 2, character's index in string : 23
NSString *steSample = #"This is sample test string";
NSUInteger count = 0, length = [steSample length];
NSRange range = NSMakeRange(0, length);
while(range.location != NSNotFound)
{
range = [steSample rangeOfString: #"i" options:0 range:range];
if(range.location != NSNotFound)
{
range = NSMakeRange(range.location + range.length, length - (range.location + range.length));
count++;
if (count == 2)
{
NSLog(#"%d", range.location); // print 6 which is location of second 'i'
}
}
}

Key-Value Coding Get Element in List

I have two objects:
#interface AObject : NSObject
#property NSArray *bObjects;
#end
#interface BObject : NSObject
#property NSString *name;
#end
Using key-value coding on an instance of AObject, I can get the list of bObjects (#"self.bObjects"), and a list of bObjects' names (#"self.bObjects.name").
However, what I want is the name of only the first of bObjects. My gut is that key-value coding should support list subscripting, like this: #"bObjects[0].name".
But that doesn't seem to exist. How do I get a single entity; the name of an AObject's first BObject, using key-value coding?
Footnote: I realized in my last question I was stupidly conflating NSPredicate and KV-coding.
As Martin R mentioned in the comments, currently the best option would be to create a firstBObject property in the AObject class.
AObject.h/m
#class BObject;
#interface AObject : NSObject
+ (AObject*)aObjectWithBObjects:(NSArray*)bObjects;
#property NSArray *bObjects;
#property (nonatomic, readonly) BObject *firstBObject;
#end
#implementation AObject
+ (AObject*)aObjectWithBObjects:(NSArray*)bObjects
{
AObject *ao = [[self alloc] init];
ao.bObjects = bObjects;
return ao;
}
- (BObject*)firstBObject
{
return [self.bObjects count] > 0 ? [self.bObjects objectAtIndex:0] : nil;
}
#end
BObject.h/m
#interface BObject : NSObject
+ (BObject*)bObjectWithName:(NSString*)name;
#property NSString *name;
#end
#implementation BObject
+ (BObject*)bObjectWithName:(NSString *)name
{
BObject *bo = [[self alloc] init];
bo.name = name;
return bo;
}
#end
Usage:
NSArray *aobjects = #[
[AObject aObjectWithBObjects:#[
[BObject bObjectWithName:#"A1B1"],
[BObject bObjectWithName:#"A1B2"],
[BObject bObjectWithName:#"A1B3"],
[BObject bObjectWithName:#"A1B4"]
]],
[AObject aObjectWithBObjects:#[
[BObject bObjectWithName:#"A2B1"],
[BObject bObjectWithName:#"A2B2"],
[BObject bObjectWithName:#"A2B3"],
[BObject bObjectWithName:#"A2B4"]
]],
[AObject aObjectWithBObjects:#[
[BObject bObjectWithName:#"A3B1"],
[BObject bObjectWithName:#"A3B2"],
[BObject bObjectWithName:#"A3B3"],
[BObject bObjectWithName:#"A3B4"]
]]
];
NSLog(#"%#", [aobjects valueForKeyPath:#"firstBObject.name"]);
Results
(
A1B1,
A2B1,
A3B1 )
So as it turns out, I had the fortune of being able to simply override -valueForKey: in the root class (AObject). It bears repeating that -valueForKeyPath: calls -valueForKey: on every key, which is cool.
Since that might not be applicable to everyone, and this might be too much manipulation of default, expected behavior, this definitely not the "right" answer.
But here it is anyway:
- (id)valueForKey:(NSString *)string
{
if ([string characterAtIndex: [string length] - 1] == ']') // Trying to subscript
{
NSRegularExpression *subscriptRegex = [[NSRegularExpression alloc] initWithPattern: #"([a-zA-Z]+)\\[([0-9]+)\\]"
options: (NSRegularExpressionOptions)0
error: nil];
NSString *key = [subscriptRegex stringByReplacingMatchesInString: string
options: (NSMatchingOptions)0
range: NSMakeRange(0, [string length])
withTemplate: #"$1"];
id valueForKey = [self valueForKey: key];
if (!key || !valueForKey || ![valueForKey respondsToSelector: #selector(objectAtIndexedSubscript:)])
return nil;
NSInteger index = [[subscriptRegex stringByReplacingMatchesInString: string
options: (NSMatchingOptions)0
range: NSMakeRange(0, [string length])
withTemplate: #"$2"] integerValue];
if ((index < 0) || (index >= [valueForKey count]))
return nil;
return [valueForKey objectAtIndexedSubscript: index];
}
return [super valueForKey: string];
}

Resources