iOS 输入框如何限制字符长度和emoji
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了iOS 输入框如何限制字符长度和emoji相关的知识,希望对你有一定的参考价值。
参考技术A我们经常会遇到这样的需求,比如手机输入框限制 11 位数字,个人简介最多不超过英文最多 100 个字,中文最多 50 个字,个人昵称不能使用 emoji 表情等等。
在上一篇文章了解了编码的基础上,我们来看下如何解决这些需求问题。
我们可以知道 emoji 表情其实是由一个或多个 Unicode 编码点组成的字符串,而且 emoji 表情对应这一定的码元范围。
因此这里如果要判断一个字符串里面是否包含 emoji 表情,就要解决两个问题:
在ios中 NSString 可以通过 enumerateSubstringsInRange:options:usingBlock: 方法。这个方法把 Unicode 抽象的地方隐藏了,能让你更轻松的循环字符串里面的组合字符串,单词,行,句子,段落。
你甚至可以加上 NSStringEnumerationLocalized 这个选项,这样可以在确定词语间和句子间的边界时把用户所在区域考虑进去。要遍历单个字符,可以将参数指定为 NSStringEnumerationByComposedCharacterSequences 按字符顺序,依次遍历出相关子字符串。
这里表明了苹果想让我们把字符串看做子字符串的集合,因为:
1.单个 unichar 太小,不足以代表一个真正的 Unicode 字符。
2.一些字符由多个 unicode 码点组成。
emoji 表情对应着一定的码元范围,因此可以通过的判断字符的 unicode 编码来判断改字符是否为 emoji 编码。
但这里有个问题,就是 emoji 对应的码元范围会随着系统版本的而改变,因为每次版本更新可能会添加新的 emoji 表情,因此这个判断方法,需要一直更新,那有没有一种好的方法可以长期有效判断呢。
在我们长期的印象中, emoji 表情都是带有色彩的,苹果键盘自带的 emoji 表情,从现在看来一直都是带有色彩的,而常规的文本一般都是黑色的,因此这里可以有如下解决方案:
具体实现如下:
当然这个方法只适合对少量的字符串,因为如果字符串比较长,利用该方法进行解析判断会耗费 CPU 资源。
因此我们可以结合上面的 emoji 对应的码元范围和下面是否包含颜色来判断,对应字符串是否包含 emoji 表情,这样准确性会高点,但对于一些第三方的键盘如搜狗输入法里面的一些表情,还是不能很好过滤。
如果是 swift 语言,因为 Swift 5.0 ,它带有一个新的 Unicode.Scalar.Properties 类,我们可以利用这个类的方法,向 Character 和 String 类添加一些帮助属性。这里会:
同样 swift 上的该方法对于第三方键盘上的部分表情判断也没办法做到百分百准确。
比如一段个人简介中经常是禁止输入表情,但允许输入中英文,如果中文要算 2 个字符,英文算 1 个字符,如何准确的算出,该字符串的长度。
因为这里的汉字算 2 个字节,英文算 1 个字节,因此应该使用 GB_18030_2000 编码来计算字符串的长度。
GB_18030_2000 主要有以下特点:
GB_18030_2000 编码:
我们常用的汉字是 3500 个,都包含在双字节部分,因此使用 GB_18030_2000 来计算字符串长度可以完美的解决我们的需求。
基于以上的知识,我写了一个输入框拦截器 FJFTextInputIntercepter ,该拦截器可以通过设置对应的参数来对输入框的输入进行限制:
这里我用了两种方式来写这个拦截器:
Unicode与JavaScript详解
从Emoji的限制到Unicode编码
js emoji表情长度判断
1、需求:输入框长度限制为10个字符,包括表情。超出长度提示。
注:iPhone手机自定义的表情,有四个小人的,三个小人的,主要是长度还都不一样。有的表情可能一个就超出了长度限制(10),比如???????????这个表情长度为11,当然我这个长度设置的比较小,可以随意设置。
查阅资料的过程中发现了lodash可以处理数组,并且可以处理表情。
console.log(_.toArray(‘12??‘).length); // --> 3);
这样的话就能符合我截取的条件了。判断如果数组的某一个长度超出我的限制长度,就截取数组。
本来这样就可以了,但是就为了转这个引入一个文件,也不合适。于是我就把源码里面的一些符合我的需要的内容摘出来。
let rsAstralRange = ‘\\ud800-\\udfff‘,
rsZWJ = ‘\\u200d‘,
rsVarRange = ‘\\ufe0e\\ufe0f‘,
rsComboMarksRange = ‘\\u0300-\\u036f‘,
reComboHalfMarksRange = ‘\\ufe20-\\ufe2f‘,
rsComboSymbolsRange = ‘\\u20d0-\\u20ff‘,
rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange;
let reHasUnicode = RegExp(‘[‘ + rsZWJ + rsAstralRange + rsComboRange + rsVarRange + ‘]‘);
let rsFitz = ‘\\ud83c[\\udffb-\\udfff]‘,
rsOptVar = ‘[‘ + rsVarRange + ‘]?‘,
rsCombo = ‘[‘ + rsComboRange + ‘]‘,
rsModifier = ‘(?:‘ + rsCombo + ‘|‘ + rsFitz + ‘)‘,
reOptMod = rsModifier + ‘?‘,
rsAstral = ‘[‘ + rsAstralRange + ‘]‘,
rsNonAstral = ‘[^‘ + rsAstralRange + ‘]‘,
rsRegional = ‘(?:\\ud83c[\\udde6-\\uddff]){2}‘,
rsSurrPair = ‘[\\ud800-\\udbff][\\udc00-\\udfff]‘,
rsOptJoin = ‘(?:‘ + rsZWJ + ‘(?:‘ + [rsNonAstral, rsRegional, rsSurrPair].join(‘|‘) + ‘)‘ + rsOptVar + reOptMod + ‘)*‘,
rsSeq = rsOptVar + reOptMod + rsOptJoin,
rsSymbol = ‘(?:‘ + [rsNonAstral + rsCombo + ‘?‘, rsCombo, rsRegional, rsSurrPair, rsAstral].join(‘|‘) + ‘)‘;
let reUnicode = RegExp(rsFitz + ‘(?=‘ + rsFitz + ‘)|‘ + rsSymbol + rsSeq, ‘g‘);
export function toArray (val) { // 字符串转成数组
return hasUnicode(val)
? unicodeToArray(val)
: asciiToArray(val);
}
export function hasUnicode (val) {
return reHasUnicode.test(val);
}
export function unicodeToArray (val) {
return val.match(reUnicode) || [];
}
export function asciiToArray (val) {
return val.split(‘‘);
}
是的,一大堆正则。看着就头疼。这个方法可以满足,把表情转成数组中的一份子。这样的话,我们只用判断数组就好了。
然后根据得到的数组,去挨个判断每一个的长度;代码如下:
let strarr = utils.toArray(val);
let str = ‘‘, strlen = 0, num = 0, lastarr = [];
for (let i = 0;i < strarr.length;i++) {
strlen += strarr[i].length; // 数组中每一个字符的长度相加
if (strlen > this.limit) { // 如果长度大于限制
num = i; // 记录下到第几个开始超出限制
lastarr = strarr.slice(0, this.limit); // 取出限制内的数组
this.$toast(‘长度超出了‘);
break; // 退出循环
// return;
}
}
if (strlen > this.limit) { // 如果输入的第一个数长度大于限制的表情
for (var j = 0;j < num;j++) {
str += lastarr[j]; // 取出限制内的数组的字符
}
this.currentValue = str;
}
其实这块也可以封装一个方法调用。
以上是关于iOS 输入框如何限制字符长度和emoji的主要内容,如果未能解决你的问题,请参考以下文章