1.前言
写这些文字,只是因为昨天纠结了大半天的时间都去怎样把文件中的字符串分离出来,按照英文单词和翻译的方式。最后是弄出来了,但是代码执行的效率很低,以致最后不得不放弃这种方法。说道最后其实就是分离字符串使用的规律不一样,造成的。但是它还是困扰了我大半天,其实就是自己的思维一直都挑不出来,这才是问题的核心。以前搞过单片机和电路什么的,自己的业余爱好也是搞单片机电路。现在开始了真正的纯软件编程就只好暂时放一段时间了。一直自己的思维也还是停留在面向过程的角度,还不能很好的以面向对象的方法取编程。最后这个小项目做完了,之前的一些思考也不断的得到了验证,就好像之前公司老总说的那样,就是我们对我们要研究的对象没弄清楚。学习也要不断的总结和思考。
2.言归正传
项目需求:有一个保存有字典英文和翻译的txt文档,现在需要使用它实现一个简单的英汉字典功能,在终端输入和输出。需求就是这样了。
需求分析:
目的:实现一个英汉字典;
功能:终端输入一个英文单词,终端输出该单词的翻译,没有该单词就打印输入错误;
研究对象:在做题之前,先仔细看看我们的保存有数据的txt文档里面内容;
对象的规律是什么?
在写出较为理想的方法之前,先说说我的初始想法。
找规律:
1)英文单词都是以#开始的,然后换行显示翻译的内容;
2)翻译的内容都是以Trans:开始的;
3) 翻译和单词各自成行;
4)英文单词都是小写 除了Trans外;
5)不同词性的翻译部分使用的@分开的。
解题思路:
1)首先分离出英文单词;
2)分离出翻译
3)把翻译和单词分别以value和key的形式存入一个字典里面
3.难点——怎么分离?
下面我就直接贴我的代码来说说我起初是怎么分离的。
- (NSDictionary *)getDiceFromUrl:(NSString *)Url{ NSMutableDictionary * myDice = [[NSMutableDictionary alloc] init]; AcceptString * acc = [[AcceptString alloc] initWithUrl:Url]; NSString * myStr = [[NSString alloc] initWithString:[acc getString]]; //将dict.txt 文件里面的内容保存起来 NSUInteger line = [acc countOfSubstring:@"#" inString:myStr]; NSLog(@"line = %ld",line); //line = 43084 NSMutableString * muStr = [[NSMutableString alloc] initWithString:myStr]; for (NSUInteger i = 0; i < 100;i ++) { NSRange r0 = [muStr rangeOfString:@"#"]; NSRange r1 = [muStr rangeOfString:@"\n"]; [muStr deleteCharactersInRange:r1]; //删除掉第一个换行 NSRange r2 = [muStr rangeOfString:@"Trans"]; NSRange r3 = [muStr rangeOfString:@"\n"];//第二个换行 NSString * subStr0 = [muStr substringWithRange:NSMakeRange(r0.location + 1,(r1.location - r0.location - 1))]; //得到单词部分 NSString * subStr1 = [muStr substringWithRange:NSMakeRange(r2.location, (r3.location - r2.location))]; //得到Trans及其所在行的部分 就是翻译部分 [myDice setValue:subStr1 forKey:subStr0];//放进字典里面去 [muStr deleteCharactersInRange:NSMakeRange(r0.location, r3.location)]; //删除掉第一个单词机器翻译 NSRange r4 = [muStr rangeOfString:@"#"];//第二个#的位置 muStr = [[NSMutableString alloc] initWithString:[muStr substringFromIndex:r4.location]];//从第二个#开始的后面部分 且包含第二个#号 的子串 } return myDice; }
我们看见了,其实代码量也没有多大,但是里面有个for循环。循环100次,没问题,循环1000次没问题,系统反应都很快。但是这里是循环line =43084次。而且循环里面的操作和比较多的。这就是我起初的一种分离的方法。导致最后程序都无法编译出来了,进入漫长的等待中了,等待最后我放弃了。其实上面的我方为我认为是一点问题都没有,我也验证了在i = 100和1000的情况下,都没问题,实际字典里面的数据也是没问题的。如果你和我头同样的想法,不是错,你可以试试,因为你不试,你不知道自己的问题出在哪里,没有深入的思考很难有进步。
后来被点拨了一下,跳出了原有的思维逻辑了。下面来看看这种较好得解法。
4.回头再看需求
1)多看看我们的保存有字典数据的文档;
2)每行不都是以换行符\n结尾的吗?
3)如果以换行符来分离这个文档中的字符串,保存进数组里面的,数字相邻的两个元素的值一个就是单词,一个就是这个单词对应的翻译了。
4)这种方法怎样呢?试试不就知道了。
很快就有了下面的代码了:在有些地方和上面有些修改,但是不影响其他部分。
//获取文件路劲,存入一个数组中 - (NSDictionary *)newDiceFromUrl:(NSString *)Url{ _myStr = [[NSString alloc] initWithContentsOfFile:Url encoding:NSUTF8StringEncoding error:nil]; //将文件里的内容保存在_myStr中 NSArray * newArray = [_myStr componentsSeparatedByString:@"\n"]; //把字符串以换行符分离,保存进数组 NSUInteger newLine = [newArray count]; //newLine = 86168 for (int i = 0; i < newLine; i+=2) { NSString * trans = [newArray[i + 1] substringFromIndex:6]; //去除掉trans: NSString * word = [newArray[i] substringFromIndex:1];//去除掉# NSString * newtrans = [trans stringByReplacingOccurrencesOfString:@"@" withString:@"\n"]; //遇见@就换行 [_myDice setValue:newtrans forKey:word]; } return _myDice; }
第一种方法里面我们知道文档的line = 43084,其实这个是单词的个数,不是真正的行数,下面的代码中的 newLine = 86168,才是真的这个文档的行数,其实我们早就知道两者之间的关系了,也就不必再去纠结这个问题了。前面的一些什么的并不会占用太多的系统时间和内存。主要是for循环里的内容。以前我们在写单片机软件延时程序的时候不是这么写的吗?
void delay(int time) { int i,j; for (i = 0;i < 100; i ++) { for (j = 0; j < time; j ++); } }
通过控制for循环里面执行的次数来控制延时长度的吗?内循环里面的
for (j = 0; j < time; j ++);
就是我们需要控制的延时长度。我们再来看看上面的两者方法的两段代码的for循环和里面的内容。
相同点
两个的循环次数都是一样的。一个line = 43084次,一个的newLine是line的倍数,但是循环步调是i+=2,不是i++,所以循环次数也就是一样的了。
不同点
循环里面的代码数,两段代码里面的内容和执行的动作我们一看就能看出来,哪个的循环速度快哪个的慢了。不用我多说了。关于两者分离的方法都说了,字符串的处理也字代码的注释中了。
终端输入
项目的核心部分,我们做完了,我们再来实现终端输入部分的了。
在动手写代码之前,我们还是看看上面的规律,需要被翻译的单词都是小写。好了,要实现这么一个终端输入也就不难了。
//接收输入字符,转换成OC的字符串 大写转换为小写 - (NSString *) getInputWord{ char p[20] = {'\0'}; //设定单词的最大长度为20 printf("请输入你要查询的单词:\n"); scanf("%s",p); NSString * instr = [[NSString alloc] initWithUTF8String:p]; _word = [instr lowercaseString]; return _word; }
这里为什么要加一个大写转小写呢?如果我们终端输入的是一个大写的单词,难道我们就提示没有这个单词了吗?显然不难这么操作。
终端输出
下面就是输出了,其实也就是怎么输出形式了。我做的事最简单的了。
- (void)myDice{ Dice * myDice = [[Dice alloc] init]; Input * myInput = [[Input alloc] init]; NSDictionary * newDice = [myDice newDiceFromUrl:@"/Users/qf/Desktop/2015.07.24/字典项目/dict.txt"]; while (1) { NSString * s2 = [myInput getInputWord]; NSString * result = [newDice objectForKey:s2]; if (result != nil) { printf("%s\n",[[newDice objectForKey:s2] UTF8String]); } else printf("没有找到你输入的单词!\n"); } }
我们简单解释一下这段代码:
第一行:创建一个字典对象myDice;
第二行:创建一个输入对象myInput;
第三行:创建一个保存有数据的字典;
第四行:while(1)大循环,我们不难在查了一个单词就是编译一下再查询把;
第五行:把接收到得输入保存在新建的声明的字符串s2中;
第六行:声明一个字符串result,保存字典newDice中键值key为s2对应的value;result 缺省值是nil,感觉先给它一个初始值比较好;
第七行:判断result是否为空;如果不是空举使用printf打印被vaule被准换为C字符串的结果;
第八行:如果result为nil就提示没有查到这个单词。
至此整个工程就完了,至于主函数里面的内容是什么?其实就是一行代码。
[[[Dice alloc] init] myDice];
编译后就可以使用这个字典了。看图看结果。
5.总结
这个小的项目难吗?不难。一步一的写出来就OK了。没什么技巧性的东西。
这个项目使用到了那些知识点呢?数组、字符串和字典,但是也都是一些基本的方法的调用。
为什么自己起初没想到好的方法?还是自己的思维问题。看待问题的角度问题。我对我们的对象还研究的不清楚。
版权声明:本文为博主原创文章,未经博主允许不得转载。