Android限制输入框10个汉字或20个字母完美实现

在android 开发中,经常会遇到要求输入框内输入的文本内容限制10个汉字或20个字母的要求。之前也在网上看了很多解决方案,效果都不是很好,大多数都是直接取字符串的length()作为限定的判断依据,这个思路是非常不对的,单纯的用String.length(),去判断字符串的长度,字母和汉字的长度一样,因此我们要换一个思路去想。

根据“10个汉字或20个字母的要求”,我们可以看出,这里的汉字和字母的长度关系比值是1:2的关系,因此我们要对字符串进行编码,这个编码就是要实现这个汉字和字母1:2的比值关系,这里我们用GB2312编码,不同的编码格式,比值关系不一样,这里大家要注意!!!

例如:

	String content = editText.getText().toString();
	byte[] bt = content.getBytes("gb2312");
	这里就是拿到输入框里数据,并将字符串编码后放入byte[] 数组中。
 
    接下来就是要判断长度,这里注意,用“gb2312”编码,按上述“10个汉字或20个字母”要求,最大长度就是20
	
	if(bt.length >20)
	{
		要处理的操作....
	}
 
	这里大家好要注意一个地方,就是一旦字符串长度超了之后的截取和转换,以及光标的位置问题,特别是后者 很多人都会遗忘。
首先是截取,将超过的字符串截取,当然,这里一定要先编码后在截取,而且是byte[]数组截取,这里我向大家提供一个方法
	private byte[] subBytes(byte[] src, int begin, int count) {
    		byte[] bs = new byte[count];
    		System.arraycopy(src, begin, bs, 0, count);
    		return bs;
}
使用的时候直接:
	String str = editable.toString();
	byte[] bt2 = str.getBytes("gb2312");
	byte[] bt3 = subBytes(bt2,0,20);
	截取好后,当然也要把byte数组里的内容转成字符串形式展现啊,这里我向大家提供一个方法
	private String gbToString(byte[] data) {
    		String str = null;
    	try {
        str = new String(data, "gb2312");
    		} catch (UnsupportedEncodingException e) {
    	}
    	return str;
}
使用时直接
	String newStrs = gbToString(bt3);
	editText.setText(newStrs);
最后就是光标的问题,一定要放到最后面!!!
int selEndIndex = Selection.getSelectionEnd(editable);
//设置新光标所在的位置
Selection.setSelection(editable, selEndIndex);

当然,这个程序写到这,看似已经可以可以实现功能了,但若重新回顾一遍逻辑,还是能发现一个漏洞的。可能有人会不明白,我就直接分享一下BUG图吧:

为什么会出现这个BUG?其实关键就在字符串最后的截取上!汉字和字母的关系是1:2,如果用户输入9个汉字后,在输入一个字母,那么此时的长度19。这时候如果最后在输入一个汉字,那么长度就是21,截取时保留前20,导致最后一个汉字被切割一半,然后在转码成字符汉字时必然会乱码。怎样解决这个BUG?其实方法有很多,我也走过一些弯路,直到蹲坑无聊时突然想到一个很简单的处理方法。
1、既然是截取最后一个字符转换后出现的问题,那我们就判断转后的字符串最后一个字符是不是乱码的,如果是那就截掉,不是就保留。由于输入框只准保留汉字和英文字母,所以我们就直接判断最后一个字符是不是汉字或字母就好了。这里我提供两个判断方法,这两个方法我都放到StringUtils类中了
 
/**
 * 判断字符串是否包含中文
 *
 * @param str
 * @return
 */
public static boolean isContainChinese(String str) {
    Pattern p = Pattern.compile("[\u4e00-\u9fa5]");
    Matcher m = p.matcher(str);
    return m.find();
}
/**
 * 判断字符串是否包含字母
 *
 * @param str
 * @return
 */
public static boolean isContainLetters(String str) {
    for (char i = 'A'; i <= 'Z'; i++) {
        if (str.contains(String.valueOf(i))) {
            return true;
        }
    }
    for (char i = 'a'; i <= 'z'; i++) {
        if (str.contains(String.valueOf(i))) {
            return true;
        }
    }
    return false;
}
判断方法有了,接下来就要把漏斗补上:
 
String temp = String.valueOf(newStrs.charAt(newStrs.length()-1));
boolean flag = StringUtil.isContainChinese(temp);
boolean flag2 = StringUtil.isContainLetters(temp);
if(!flag && !flag2 ){
    String newStrs2 = newStrs.substring(0,newStrs.length()-1);
    editText.setText(newStrs2);
}else {
    editText.setText(newStrs);
}
这里的二次截取的条件就是转换后的字符串最否一个字母即不是汉字也不是字母才会执行(如果各位还想包含其他字符,可以再加判断的)
现在再看看效果:

最后的乱码就被截取掉了。可以说很完美了。
 
还有一个知识点要提一下,关于文字的EditText文本监听,我个人认为用TextWatcher效果最好,因为它可以很方便自定义内容实现。
说了这么多,给大家奉献完整代码才是硬道理。
public class WatcherText implements TextWatcher {

    private int maxLen = 0;
    private EditText editText = null;

    public WatcherText(int maxLen, EditText editText) {
        this.maxLen = maxLen;
        this.editText = editText;
    }

    public void afterTextChanged(Editable arg0) {
        // TODO Auto-generated method stub

    }

    public void beforeTextChanged(CharSequence arg0, int arg1, int arg2,
                                  int arg3) {
        // TODO Auto-generated method stub

    }

    public void onTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {
        try {
            // TODO Auto-generated method stub
            Editable editable = editText.getText();
            String content = editText.getText().toString();

            byte[] bt = content.getBytes("gb2312");
            if(bt.length >maxLen)
            {
                ToastUtil.showErrorInfoTip("输入字符数超过限制");
                int selEndIndex = Selection.getSelectionEnd(editable);
                String str = editable.toString();
                byte[] bt2 = str.getBytes("gb2312");
                byte[] bt3 = subBytes(bt2,0,maxLen);
                String newStrs = gbToString(bt3);
                String temp = String.valueOf(newStrs.charAt(newStrs.length()-1));
                boolean flag = StringUtil.isContainChinese(temp);
                boolean flag2 = StringUtil.isContainLetters(temp);
                if(!flag && !flag2 ){
                    String newStrs2 = newStrs.substring(0,newStrs.length()-1);
                    editText.setText(newStrs2);
                }else {
                    editText.setText(newStrs);
                }
                editable = editText.getText();
                // 新字符串的长度
                int newLen = editable.length();
                // 旧光标位置超过字符串长度
                if(selEndIndex >= newLen)
                {
                    selEndIndex = editable.length();
                }
                //设置新光标所在的位置
                Selection.setSelection(editable, selEndIndex);

            }

        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

    }

    private byte[] subBytes(byte[] src, int begin, int count) {
        byte[] bs = new byte[count];
        System.arraycopy(src, begin, bs, 0, count);
        return bs;
    }

    private String gbToString(byte[] data) {
        String str = null;
        try {
            str = new String(data, "gb2312");
        } catch (UnsupportedEncodingException e) {
        }
        return str;
    }

}


外面使用的时候直接
EditText editText = (EditText) findViewById(R.id.entry);
editText.addTextChangedListener(new WatcherText(MAX_NUM, editText));

如有不对的地方,欢迎各位大神指正,谢谢。

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
你可以结合上面提到的正则表达式来实现这个限制。具体做法是在输入框的文本变更事件中,使用正则表达式匹配当前文本是否符合要求,然后根据匹配结果设置输入框的可用状态。以下是一个简单的示例代码: ```python import re from PyQt5.QtWidgets import QLineEdit class ChineseLineEdit(QLineEdit): def __init__(self, parent=None): super().__init__(parent) self.setPlaceholderText("请输入汉字") self.textChanged.connect(self.check_input) self.pattern = re.compile(r'^[\u4e00-\u9fa5]{1,10}$') def check_input(self): text = self.text() if self.pattern.match(text): self.setReadOnly(False) else: self.setReadOnly(True) ``` 上述代码中,我们创建了一个名为 `ChineseLineEdit` 的自定义文本框类,继承自 `QLineEdit`。在构造函数中,我们设置了一个提示文本,然后连接了 `textChanged` 事件到 `check_input` 方法上,这个方法会在文本变更时被调用。`pattern` 变量是我们预先编译好的正则表达式,用于匹配汉字且长度不为 0 且不超过 10 个字符字符串。 `check_input` 方法首先获取当前文本框中的文本,然后使用正则表达式的 `match` 方法来判断当前文本是否符合要求。如果符合要求,我们将文本框的只读属性设置为 False,否则设置为 True,这样就可以限制用户只能输入汉字且长度不为 0 且不超过 10 个字符字符串了。 你可以将上述代码保存到一个 Python 文件中,然后在你的项目中导入使用这个自定义文本框组件,如下所示: ```python from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout app = QApplication([]) window = QWidget() layout = QVBoxLayout() layout.addWidget(ChineseLineEdit()) window.setLayout(layout) window.show() app.exec_() ``` 这样就可以在窗口中显示一个限制用户只能输入汉字的文本框了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值