美文网首页iOS DeveloperiOS新手学习iOS_UIkit
iOS开发--UITextField限制字数(中文,数字),过滤

iOS开发--UITextField限制字数(中文,数字),过滤

作者: FR_Zhang | 来源:发表于2016-09-01 10:44 被阅读3452次

    前言

    这是在我项目开发中遇到的问题,主要是给创建的作品保存名字,这样我们就会涉及到名称字数和特殊字符的限制,目前涉及到用户输入的大部分解决方案就是UITextField和UITextView,两者的原理差不多,那么下面就针对UITextField进行简单的分享.

    补充:目前为止XCode版本更新后(目前为8.1)对开发者账户进行了相关的限制,至于何种限制,目前影响最大的就是从网上下载下来的项目不能用了,原因是证书等问题,所以给大家一个建议,小程序可以用模拟器的用模拟器,用到真机的尽可能的选择将你开发组的账号,这个一般公司都会配备.这里简单说一下,详细的可以参考我的另外一边文章:iOS坑--XCode8 的一些问题,希望对大家有所帮助.

    正文

    1.准备工作

    1).创建属性
    由于项目中的UITextField为StoryBoard控件,创建省略

    /// 记录显示剩余个数
    @property (weak, nonatomic) IBOutlet UILabel *totalCharacterLabel;
    /// 输入UITextField
    @property (weak, nonatomic) IBOutlet UITextField *nameField;
    

    2).设置最大限制数

    static NSInteger CharacterCount = 8;
    

    3).设置代理

    self.nameField.delegate = self;
    

    4).遵循代理

    @interface ViewController () <UITextFieldDelegate>
    

    2.原理

    首先我们需要区分的是UITextField的输入分为两个阶段,即为输入阶段和确定输入阶段,输入阶段这里主要针对的是中文的输入,这里不需要做严格的判断要求,再就是确定输入阶段,也就是UITextField的输出显示阶段,这里需要排除空格,emoji等特殊字符和字数的限制(截取有效字符).

    3.观察者

    1).添加观察者

    [self.nameField addTarget:self action:@selector(textFieldChanged:)forControlEvents:UIControlEventEditingChanged];
    

    2).执行观察者对应的方法
    在方法中,特地针对目前iOS支持的第三方输入法做出的解决方案

    - (void)textFieldChanged:(UITextField *)textField {
        NSString *toBeString = textField.text;
        if (![self isInputRuleAndBlank:toBeString]) {
            textField.text = [self disable_emoji:toBeString];
            return;
        }
        NSString *lang = [[textField textInputMode] primaryLanguage]; // 获取当前键盘输入模式
        //简体中文输入,第三方输入法(搜狗)所有模式下都会显示“zh-Hans”
        if([lang isEqualToString:@"zh-Hans"]) {
            UITextRange *selectedRange = [textField markedTextRange];
            //获取高亮部分
            UITextPosition *position = [textField positionFromPosition:selectedRange.start offset:0];
            //没有高亮选择的字,则对已输入的文字进行字数统计和限制
            if(!position) {
                NSString *getStr = [self getSubString:toBeString];
                if(getStr && getStr.length > 0) {
                    textField.text = getStr;
                }
            }
        } else{
            NSString *getStr = [self getSubString:toBeString];
            if(getStr && getStr.length > 0) {
                textField.text= getStr;
            }
        }
    }
    

    4.执行代理

    1). 在UITextField的代理中,主要是对确定输入阶段的判断,确定没有空格和空

    - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
        if ([self isInputRuleNotBlank:string] || [string isEqualToString:@""]) {//当输入符合规则和退格键时允许改变输入框
            return YES;
        } else {
            NSLog(@"超出字数限制");
            return NO;
        }
    }
    

    2). return收回键盘

    - (BOOL)textFieldShouldReturn:(UITextField *)textField {
        [self.view endEditing:YES];
        return YES;
    }
    

    5.输入内容判断(正则判断)

    1).字母、数字、中文正则判断(不包括空格)

    - (BOOL)isInputRuleNotBlank:(NSString *)str {
        NSString *pattern = @"^[a-zA-Z\u4E00-\u9FA5\\d]*$";
        NSPredicate *pred = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", pattern];
        BOOL isMatch = [pred evaluateWithObject:str];
        return isMatch;
    }
    

    2).字母、数字、中文正则判断(包括空格)(在系统输入法中文输入时会出现拼音之间有空格,需要忽略,当按return键时会自动用字母替换,按空格输入响应汉字)

    注意: 因为考虑到输入习惯,许多人习惯使用九宫格,这里在正常选择全键盘输入错误的时候,进行九宫格判断,九宫格对应的是下面➋➌➍➎➏➐➑➒的字符.目前项目已经在github上进行更新.
    - (BOOL)isInputRuleNotBlank:(NSString *)str {
        NSString *pattern = @"^[a-zA-Z\u4E00-\u9FA5\\d]*$";
        NSPredicate *pred = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", pattern];
        BOOL isMatch = [pred evaluateWithObject:str];
        // 这里是后期补充的内容:九宫格判断
        if (!isMatch) {
            NSString *other = @"➋➌➍➎➏➐➑➒";
            unsigned long len=str.length;
            for(int i=0;i<len;i++)
            {
                unichar a=[str characterAtIndex:i];
                if(!((isalpha(a))
                     ||(isalnum(a))
                     ||((a=='_') || (a == '-'))
                     ||((a >= 0x4e00 && a <= 0x9fa6))
                     ||([other rangeOfString:str].location != NSNotFound)
                     ))
                    return NO;
            }
            return YES;
            
        }
        return isMatch;
    }
    

    3).过滤字符串中的emoji

    - (NSString *)disable_emoji:(NSString *)text {
        NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"[^\\u0020-\\u007E\\u00A0-\\u00BE\\u2E80-\\uA4CF\\uF900-\\uFAFF\\uFE30-\\uFE4F\\uFF00-\\uFFEF\\u0080-\\u009F\\u2000-\\u201f\r\n]"options:NSRegularExpressionCaseInsensitive error:nil];
        NSString *modifiedString = [regex stringByReplacingMatchesInString:text
                                                                   options:0
                                                                     range:NSMakeRange(0, [text length])
                                                              withTemplate:@""];
        return modifiedString;
    }
    
    

    6.截取字符串(重点)

    有趣的是,根据不同的需求做出了两种不同的方案,就是中文按照原理是占用两个字节来算,但是有很多需求只是简单地计算个数,即为表面上看到的个数,所以从用户角度来讲,个数更符合用户审美.但是从一个程序员角度而言,两个限制一个中文,没错,程序员,就是这么矫情,反正,下面做出了两种不同的解决方案,根据你的需求而定吧

    -(NSString *)getSubString:(NSString*)string
    {
        /// 第一种:两个字节一个中文
        //    NSStringEncoding encoding = CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingGB_18030_2000);
        //    NSData* data = [string dataUsingEncoding:encoding];
        //    NSInteger length = [data length];
        //    if (length > CharacterCount) {
        //        NSData *data1 = [data subdataWithRange:NSMakeRange(0, CharacterCount)];
        //        NSString *content = [[NSString alloc] initWithData:data1 encoding:encoding];//注意:当截取CharacterCount长度字符时把中文字符截断返回的content会是nil
        //        if (!content || content.length == 0) {
        //            data1 = [data subdataWithRange:NSMakeRange(0, CharacterCount - 1)];
        //            content =  [[NSString alloc] initWithData:data1 encoding:encoding];
        //        }
        //        return content;
        //    }
        //    return nil;
       /// 第二种:按照个数进行判断
        if (string.length > CharacterCount) {
            NSLog(@"超出字数上限");
            _totalCharacterLabel.text = @"0";
            return [string substringToIndex:CharacterCount];
        }else {
            _totalCharacterLabel.text = [NSString stringWithFormat:@"%ld",(long)(CharacterCount - string.length)];
        }
        return nil;
    }
    

    其他

    点击view的其他区域收回键盘

    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
        [self.view endEditing:YES];
    }
    

    写在最后

    • 项目中遇到的问题,给予的解决方案,可能不是做完美的,但是根据需求已经达到要求,所以,如有不做指出,欢迎大家相互交流
    • 此次解决方案中,用到的正则表达式没有过多性的进行表述,因为本人对这方面还未曾涉猎,今后会做以补充
    • 按照惯例,奉上Demo地址:
      zhangfurun的Github--UITextFieldDemo-限制字数

    -----------------谢谢-----------------

    相关文章

      网友评论

      • char_hu:谢谢!刚到遇到到这块的一个问题。
      • 不是谁的李逍遥:swift版本已解决
      • 8493188d440d:有没有swift版本的
      • 在没老之前:楼主,我现在碰到一个问题,就是点击textField,然后弹出九宫格,我点击九宫格换行按钮上面的那个笑脸符号,就直接蹦了。。。为什么啊?:sob:
        还有我们填写公司名称,怎么判断到用户输入了emoji表情,然后给予提示
      • e9a11dacc81d:使用系统的九宫格输入就有问题,字符限制就没用了,可以输入一大堆
      • IOS_绿豆糕:如限制输入字节数,并且支持输入emoji 算字节数的时候 emoji怎么算?
        向晨宇:@IOS_绿豆糕 字符字节的限制处理,可查看

        http://www.iosxxx.com/blog/2016-11-27-UITextField%E6%9C%80%E5%A4%A7%E5%AD%97%E7%AC%A6%E6%95%B0%E5%92%8C%E6%9C%80%E5%A4%A7%E5%AD%97%E8%8A%82%E6%95%B0%E7%9A%84%E9%99%90%E5%88%B6.html
        IOS_绿豆糕:@FR_Zhang 现在我将最后一个字符截取出来了 想要判断是否是emoji 用swift
        FR_Zhang:这个对字符占有字节数 根据规定来的 就好比中文占有2个字节 没有为什么 至于emoji 这个可以试试 我也没试过 一般限制字数 只针对中文和英文的区别 以防特殊字符 如果特殊需求需要单独研究
      • e4320491b3da:好像系统自带的九宫格不能输入哈~
        e4320491b3da:@FR_Zhang好的~~~谢谢
        FR_Zhang:@靠装逼生存 现在已经更新了九宫格的判断,可以去github上面下载了
        FR_Zhang:这个目前为止 已经有了解决的方案 我稍后会进行页面更新
      • 小城东风:按照惯例,添加关注 :smile:
        FR_Zhang:@小城东风 谢谢。
      • 郑州程序员王一:啊啊啊啊啊,比我写的好多了。。。。
        FR_Zhang:@郑州程序猿王一 过奖过奖啦
      • 笑里剑:学习学习,我也做过个类似的。不过没用观察者,还有就是没有区分字节,看来不是个好程序猿:joy::joy::joy:
        FR_Zhang:@三千弱水东流去 大家一起学习。一起交流。这也是我工作的时候遇到的问题。估计也有不少人会用到
      • carpond:牛逼,学习,涨了点知识
        FR_Zhang:@L_Mr 哈哈。 相互交流交流
      • 燃烧的大鹅:厉害厉害,学习了
        FR_Zhang:@燃烧的大鹅 哈哈

      本文标题:iOS开发--UITextField限制字数(中文,数字),过滤

      本文链接:https://www.haomeiwen.com/subject/oiucettx.html