一行代码解决UITextField和UITextView限制字数和输入特殊字符

一.textField/textView限制字符长度

一开始我在做UITextField和UITextView限制字数
1.TextField限制字数
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(textFieldChange:) name:UITextFieldTextDidChangeNotification object:nil];
或者
[textField addTarget:self action:@selector(textFieldChange:) forControlEvents:UIControlEventEditingChanged];
然后在

-(void)textFieldChange:(UITextField *)textField{ 

     if(textField.text.length > maxNumber)
     {
        textField.text= [textField.text substringToIndex:maxNumber];
     }
 
   }

也可以在textField的代理中做相应的处理

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {} //具体实现和上面方法一样就不多说了

2.TextView限制字数
在TextView的代理中

- (void)textViewDidChange:(UITextView *)textView{
   if(textView.text.length > maxNumber) 
   {
      textView.text= [textView.text substringToIndex:maxNumber];
   }
}

以上方法是最简单的处理,如果输入英文字符完全没有问题,但是输入中文时,如果使用第三方键盘也是没有问题的,但就是在系统自带键盘输入拼音时,你就会发现有很严重的问题😂,当你输入一个拼音时,你还没有选中你要选的文字时,已经被键盘当做字母输入到textField/textView中了,这并不是你想要的结果...比如你用系统键盘输入"你好",它会把n i h a o显示在textField/textView中, 不但没有输入汉字,还每个字母占两个字符长度...

分析一下当你输入拼音时,此时你输入的拼音还是处于高亮状态,这时已经走截取字符的方法,截取完又赋值给textField/textView,所以就会出现以上的问题,处理方法就是监听系统键盘输入拼音处于高亮状态时不截取字符

/**
 textField限制字数
 */
- (void)textFieldChange:(UITextField *)textField{
    NSInteger maxNumber = 15;
    NSString *toBeString = textField.text;  
    NSString *lang = textField.textInputMode.primaryLanguage; // 键盘输入模式
    if([lang isEqualToString:@"zh-Hans"]) { //简体中文输入,包括简体拼音,健体五笔,简体手写
        UITextRange *selectedRange = [textField markedTextRange];
        //获取高亮部分
        UITextPosition *position = [textField positionFromPosition:selectedRange.start offset:0];
        //没有高亮选择的字,则对已输入的文字进行字数统计和限制
        if(!position) {
              
            if(toBeString.length > maxNumber) {
                textField.text = [toBeString substring index:maxNumber];
            }
        } else{ //有高亮选择的字符串,则暂不对文字进行统计和限制
        
        }
    }
    else{ //中文输入法以外的直接对其统计限制即可,不考虑其他语种情况
        MyLog(@"haha ");
        
        if(toBeString.length > maxNumber) {
          textField.text= [toBeString substringToIndex:maxNumber];
//此方法防止emoji表情被截断 
// 3月19日更新为
       textField.text=  [[self class] subStringWith:toBeString ToIndex:maxNumber];
        }
    }
}
//textView同上处理

完美解决使用系统键盘输入汉字出现的截取拼音字母显示在textField/textView

以上处理一般textField/textView限制字数长度

二.textField/textView限制输入特殊字符

/**
 限制输入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;
}

/**
 只能输入汉字,数字,英文,括号,下划线,横杠,空格
 */
+(NSString *)filterCharactors:(NSString *)string{
    
    NSString *regular = @"[^a-zA-Z0-9()_\u4E00-\u9FA5\\s-]"; //根据你不同的需求填写你自己的正则
    NSString *str = [[self class] filterCharactor:string withRegex:[NSString stringWithFormat:@"%@",regular]];
    return str;
}

原理是当字符串判断是否输入你要限制的字符,把要限制的字符截掉
但是当你的textField/textView既要限制字数,又要限制输入特殊字符,把上面两个方法调完,你会发现,第一个问题又出来了,而且这次是第一次用系统键盘输入汉字时正常,如果你要继续在输入时依然会把拼音当成字符输入到textField/textView里.所以对上面的方法再次进行优化

三.textField/textView限制字符长度并且限制输入特殊字符

/**
 判断NSString中是否有表情
 */
+ (BOOL)isContainsEmoji:(NSString *)string {
    __block BOOL isEomji = NO;
    [string enumerateSubstringsInRange:NSMakeRange(0, [string length]) options:NSStringEnumerationByComposedCharacterSequences usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
        const unichar hs = [substring characterAtIndex:0];
        // surrogate pair
        if (0xd800 <= hs && hs <= 0xdbff) {
            if (substring.length > 1) {
                const unichar ls = [substring characterAtIndex:1];
                const int uc = ((hs - 0xd800) * 0x400) + (ls - 0xdc00) + 0x10000;
                if (0x1d000 <= uc && uc <= 0x1f77f) {
                    isEomji = YES;
                }
            }
        } else {
            // non surrogate
            if (0x2100 <= hs && hs <= 0x27ff && hs != 0x263b) {
                if (!(9312 <= hs && hs <= 9327)) { // 9312代表①   表示①至⑯
                    isEomji = YES;
                }
            } else if (0x2B05 <= hs && hs <= 0x2b07) {
                isEomji = YES;
            } else if (0x2934 <= hs && hs <= 0x2935) {
                isEomji = YES;
            } else if (0x3297 <= hs && hs <= 0x3299) {
                isEomji = YES;
            } else if (hs == 0xa9 || hs == 0xae || hs == 0x303d || hs == 0x3030 || hs == 0x2b55 || hs == 0x2b1c || hs == 0x2b1b || hs == 0x2b50|| hs == 0x231a ) {
                isEomji = YES;
            }
            if (!isEomji && substring.length > 1) {
                const unichar ls = [substring characterAtIndex:1];
                if (ls == 0x20e3) {
                    isEomji = YES;
                }
            }
        }
    }];
    return isEomji;
}
/**
 判断是否存在特殊字符 只能输入汉字,数字,英文,括号,下划线,横杠,空格
 */
+ (BOOL)isContainsSpecialCharacters:(NSString *)searchText
{
/*此方法也可以理论上可以,但实测还是会有问题*/
//    NSString *regex = @"[^a-zA-Z0-9()_\u4E00-\u9FA5\\s-]";
//    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", regex];
//    BOOL isValid = [predicate evaluateWithObject:string];
//    return isValid; 
    
    NSError *error = NULL;
    NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"[^a-zA-Z0-9()_\u4E00-\u9FA5\\s-]"  options:NSRegularExpressionCaseInsensitive error:&error];
    NSTextCheckingResult *result = [regex firstMatchInString:searchText options:0 range:NSMakeRange(0, [searchText length])];
    if (result) {
        return YES;
    }else {
        return NO;
    }
    
}

/**
 textField限制字数
 */
+ (void)restrictionInputTextField:(UITextField *)textField maxNumber:(NSInteger)maxNumber{
    
    NSString *toBeString = textField.text;  
    NSString *lang = textField.textInputMode.primaryLanguage; // 键盘输入模式
    if([lang isEqualToString:@"zh-Hans"]) { //简体中文输入,包括简体拼音,健体五笔,简体手写
        UITextRange *selectedRange = [textField markedTextRange];
        //获取高亮部分
        UITextPosition *position = [textField positionFromPosition:selectedRange.start offset:0];
        //没有高亮选择的字,则对已输入的文字进行字数统计和限制
        if(!position) {
              
            if(toBeString.length > maxNumber) {
                textField.text = [toBeString substringToIndex:maxNumber];
            }
        } else{ //有高亮选择的字符串,则暂不对文字进行统计和限制
        
        }
    }
    else{ //中文输入法以外的直接对其统计限制即可,不考虑其他语种情况
        MyLog(@"haha ");
        
        if(toBeString.length > maxNumber) {
//            textField.text= [toBeString substringToIndex:maxNumber];
//此方法防止emoji表情被截断 
// 3月19日更新为
  textField.text=  [[self class] subStringWith:toBeString index:maxNumber];
        }
    }
    
}

最终方法

/**
 除去特殊字符并限制字数的textField
 */
+ (void)restrictionInputTextFieldMaskSpecialCharacter:(UITextField *)textField maxNumber:(NSInteger)maxNumber{
    
    if ([[self class]isContainsEmoji:textField.text]){
        textField.text = [[self class]disable_emoji:textField.text];
        return;
    }
    if ([[self class]isContainsSpecialCharacters:textField.text]){
        textField.text = [[self class]filterCharactors:textField.text];
        return;
    }
    [[self class]restrictionInputTextField:textField maxNumber:maxNumber];
}

UITextView同上方法

最最后......

最近测试妹子给测出一个问题,就是我的一个输入框是填写电话的,我的 keyboardTypeUIKeyboardTypePhonePad.理论上只能输入数字了,于是我也就偷懒没做任何判断屏蔽特殊字符,但是依然给我测出可以输入emoji表情和一些特殊字符,🤣,然后我就想应该是在其他地方复制粘贴到我的textField里吧,于是我就想到很粗鲁的方法,就是把textField的粘贴给禁掉🤔 哈哈,以下方法不建议采用,还是老老实实的吧限制特殊字符吧,但是你非要和我一样懒😂,那我也管不着🙄

//屏蔽textField粘贴
//Initialzation code
        UILongPressGestureRecognizer *longRecognizer = [[UILongPressGestureRecognizer alloc]initWithTarget:self action:@selector(addGestureRecognizer:)];
        longRecognizer.allowableMovement = 100.0f;
        longRecognizer.minimumPressDuration = 1.0;
        [self addGestureRecognizer:longRecognizer];

//重写        
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
    UIMenuController *menuController = [UIMenuController sharedMenuController];
    if (menuController) {
        //设置为不可用
        [UIMenuController sharedMenuController].menuVisible = NO;
    }
    return NO;
}


- (void)addGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
{
    //Prevent zooming but not panning
    if ([gestureRecognizer isKindOfClass:[UILongPressGestureRecognizer class]])
    {
        gestureRecognizer.enabled = NO;
    }
    [super addGestureRecognizer:gestureRecognizer];
}

如果你还有其他好的方法欢迎提出,共同学习,peace!

参考这篇文章

详细代码请查看GitHub:SDTextLimit
我的微博:slowdony

3月19更新

//防止原生emoji表情被截断
+ (NSString *)subStringWith:(NSString *)string index:(NSInteger)index{

    NSString *result = string;
    if (result.length > index) {
        NSRange rangeIndex = [result rangeOfComposedCharacterSequenceAtIndex:index];
        result = [result substringToIndex:(rangeIndex.location)];
    }

    return result;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,560评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,104评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,297评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,869评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,275评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,563评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,833评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,543评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,245评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,512评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,011评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,359评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,006评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,062评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,825评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,590评论 2 273
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,501评论 2 268

推荐阅读更多精彩内容