EditText字符限制-字节数限制-一次截取超过限制部分

Posted 斯文的皮蛋

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了EditText字符限制-字节数限制-一次截取超过限制部分相关的知识,希望对你有一定的参考价值。

 

EditText最大字符数限制

 

一、寄语:

         EditText输入最大字符个数限制实质上即事最大字节数限制,此代码通过比较输入的字符的字节数,然后一次性截取掉超过字节数限制的部分,不用单独区分中文还是英文。此代码不处理特殊字符(暂无此需求),网上很多例子都是对edittext最大字符个数(输入的字符数)限制进行编码实现,例如:同是6个中文和英文,他们占用的字节是不一样的,既然有限制肯定是对存储空间的限制,即文件名太长无法保存等,所以考虑字符串的字节数才是最主要的,而不是字符个数。同时,此例子中对超出最大字节数的字符进行一次性截取掉,而非网上大多数进行的每次删除一个,这样删除掉超出限制的字节数字符后就只会再触发一次afterTextChanged方法,便于处理。

        思路真的非常重要,希望大家多看思路、明白思路。

        转载请注明出处:http://www.cnblogs.com/wangqx/p/6096272.html 

     有任何疑问请留言,内容有不对的地方或者还可以优化,或者园友有更好的实现方式,欢迎探讨与指正 ,QQ群238696947

二、需求描述:

      对EditText字符个数限制,当用户输入字符串超长度过指定值时,不允许输入,并给出提示。不允许输入其实是用户输入了,代码中自动剪切掉超出的部分,并不是不允许输入,因为用户不输入,是没有办法判断当前的字符数是否超出限制的,只有用户输入超出了限制,才可以判断输入的字符超出了限制,进一步处理,剪切掉超出的部分,故给人的感觉是超出最大限制了不允许输入。

三、思路描述:

以在字符串中间插入字符串(插入后将会超出限制)的情况来归纳总结(其他情况如:在字符串前面插入,或者在字符串末尾插入,均可视为此种情况的特殊情况),思路很重要

1、获取改变前的字符串4、即下图中4部分

2、获取要插入的字符串、即下图中3部分

      3、依次将3中的字符串拼接到4后面,当字符串字节数超出限制时,将最后一次没有超出限制可以拼接的字符串的个数N记录下来(之所以记录个数而不是字节数,是为了截取,不可能把一个汉字分开,例如例子中一个汉字为3个字节,最大限制20个字节,就只能显示6个汉字,扔下2个字节就剩下吧,故截取的时候不能按字节截取,按字符个数截取)。此拼接只为暂时计算在字节数限制内总共可以容纳的字符串个数,

对应代码中if语句

     4、将下图3部分中超出限制的字符串删除,对应代码中s.delete操作

 

四、原理图解及效果图

其中、1为字符串改变前光标前的部分"你好",2为光标后的部分"美女",4为改变前的字符串"你好美女",3为要插入的字符串"我们都是",5为插入后没有处理的字符串"你好我们都是美女","我们都是"字符串将要插入在"你好"和"美女"之间,6/7/8/9分别对应"我"、"们"、"都"、"是" 这四个字,在拼接判断还可以插入多少字符串时用到

原理图解:

 

效果图:

    效果图:搜狗输入法、魅族手机

    log图示:

五、代码实现

MainActivity.java

代码及添加的log只考虑插入字符的情况(包括复制黏贴),不考虑删除情况,因为删除不会有字符数限制的问题,没有实际意义(不考虑删除字符同时降低了难度)。

  1 package com.example.textwatcher;
  2 
  3 import android.app.Activity;
  4 import android.os.Bundle;
  5 import android.text.Editable;
  6 import android.text.TextWatcher;
  7 import android.util.Log;
  8 import android.widget.EditText;
  9 import android.widget.TextView;
 10 import android.widget.Toast;
 11 
 12 public class MainActivity extends Activity implements TextWatcher{
 13 
 14     private static final boolean Debug = true;
 15     private static final String TAG = MainActivity.class.getName();
 16     private static final int MAX_LENGTH = 20;//最大字节数,不用区分是中文还是英文,字节数一定,可以动态插入字符个数(如:还可插入1个汉字,若是英文则还可以插入3个英文字母<手机显示一个汉字要3个字节,一个字母1个字节>),一般此值为255, 2^8 -1
 17     private EditText edittext;
 18     private TextView textview;
 19     private String temp = null;//临时变量
 20     private String name = null;//改变后的字符串
 21     private String frontString = null;//frontString是字符串 1
 22     private String middleString = null;//字符串3
 23     private String behindString = null;//字符串2
 24     private int editStart = 0;
 25     private int editEnd = 0;
 26     private int startPos = 0;//光标的位置,即1/2之间的位置
 27     private int endPos = 0;//改变文字后光标的位置
 28     @Override
 29     protected void onCreate(Bundle savedInstanceState) {
 30         super.onCreate(savedInstanceState);
 31         setContentView(R.layout.activity_main);
 32         edittext = (EditText) findViewById(R.id.et);
 33         textview = (TextView) findViewById(R.id.tv);
 34         edittext.addTextChangedListener(this);
 35     }
 36 
 37     @Override
 38     public void beforeTextChanged(CharSequence s, int start, int count,
 39             int after) {
 40         // TODO Auto-generated method stub
 41         startPos = start;//在字符串改变前保存光标的位置,即1、2之间的位置
 42         temp = s.toString();//保留字符串改变前的值 1+2、即4
 43         frontString = s.subSequence(0, startPos).toString();//frontString是字符串 1
 44         if(Debug){
 45             Log.i(TAG, "beforeTextChanged temp="+temp);
 46             Log.i(TAG, "beforeTextChanged temp.getBytes().length="+temp.getBytes().length);
 47             Log.i(TAG, "frontString="+frontString);
 48         }
 49 
 50     }
 51 
 52     @Override
 53     public void onTextChanged(CharSequence s, int start, int before, int count) {
 54         // TODO Auto-generated method stub
 55 
 56     }
 57 
 58     @Override
 59     public void afterTextChanged(Editable s) {
 60         // TODO Auto-generated method stub
 61         //此count和 beforeTextChanged方法中的count没有任何联系 
 62         int count = 0;//定义为局部变量,防止上次的值对其有影响(小编刚开始定义为了全局变量,结果引发的错误排查了很久)
 63         name = s.toString().trim();//主要是为了获取name的字节长度,为了调试用  、即5
 64         editEnd =  edittext.getSelectionEnd();
 65         behindString = name.substring(editEnd, name.length());//behindString是字符串2
 66         middleString = name.substring(startPos, editEnd);//middleString是字符串3
 67         StringBuilder sb = new StringBuilder(temp);//根据改变前的字符串构键sb   
 68         if(name.getBytes().length > MAX_LENGTH && middleString != null && middleString != ""){
 69             if(Debug){
 70                 Log.i(TAG, "*************afterTextChanged 插入后字符串字节长度超出限制  开始处理**************");
 71                 Log.i(TAG, "afterTextChanged 插入后的完整字符串字节长度  name.getBytes().length="+name.getBytes().length);
 72                 Log.i(TAG, "afterTextChanged 插入前的完整字符串 temp="+temp);
 73                 Log.i(TAG, "afterTextChanged 插入时,光标前的字符串 frontString="+frontString);
 74                 Log.i(TAG, "afterTextChanged 需要插入的字符串 middleString="+middleString);
 75                 Log.i(TAG, "afterTextChanged 插入时,光标后的字符串  behindString="+behindString);
 76                 Log.i(TAG, "afterTextChanged 需要插入的字符串字符个数   middleString.length()="+middleString.length());
 77                 Log.i(TAG, "afterTextChanged 需要插入的字符串字节数  middleString.getBytes().length="+middleString.getBytes().length);
 78             }
 79             for(int i = 0;i < middleString.length();i++){
 80                 if(Debug){
 81                     Log.i(TAG, "需要拼接的第"+i+"个字符 middleString.subSequence(i, i+1)="+middleString.subSequence(i, i+1));
 82                     Log.i(TAG, "需要拼接的第"+i+"个字符字节长度    middleString.subSequence(i, i+1).toString().getBytes().length="+middleString.subSequence(i, i+1).toString().getBytes().length);
 83                 }
 84                 //依次将3中的字符串6、7、8、9拼接上去直到拼接后的字符串字节数大于最大值为止,将最多可以拼接的数赋值给count
 85                 //例如本例子中,小编在自己手机上打印到的每个汉字占3个字节(不是应该2个字节吗,很纳闷),"你好美女"共12字节,所以还可以拼接2个汉字
 86                 //即一共可以显示6个字,18个字节。最大是20个字节,如果是7个字的话,21个字节,超出范围了。故此时count为2
 87                 //在给count赋值时,一定要把count写在if语句里面,刚开始小编把count的赋值写在了for循环里面,if语句的下面了,最后发现当if语句不成立时
 88                 //count也有值,浪费了好久才找出问题
 89                 if(sb.append(middleString.subSequence(i, i+1)).toString().getBytes().length < MAX_LENGTH){//后面有改动,需要将 "<" 修改为 "<=",如果此处需要使用"<"号,请将68行处的">"改为">="
 90                     count = i + 1;
 91                     if(Debug){
 92                         Log.i(TAG, "i="+i);
 93                         Log.i(TAG, "拼接第"+i+"个字符后的字符串   sb.toString()="+sb.toString());
 94                         Log.i(TAG, "拼接第"+i+"个字符后的字符串字节数   sb.toString().getBytes().length="+sb.toString().getBytes().length);
 95                         Log.i(TAG, "需要拼接的字符串 middleString="+middleString+"  已经拼接:"+count+"个   字符"+middleString.subSequence(0, i+1));
 96                     }
 97                 }else{
 98                     if(Debug){
 99                         Log.d(TAG, "原字符串:"+temp);
100                         Log.d(TAG, "原字符串字节数:"+temp.getBytes().length);
101                         Log.d(TAG, "需要插入的字符串:"+middleString);
102                         Log.d(TAG, "middleString:"+middleString+",一共可以拼接  "+count+"  个字符:"+ middleString.subSequence(0, count)+"  。可以插入的字符字节数:"+middleString.subSequence(0, count).toString().getBytes().length);
103                     }
104                     break;//如果if语句不成立,则直接跳出for循环
105                 }
106             }        
107             temp = new StringBuilder(frontString).append(middleString.substring(0, count)).append(behindString).toString();
108             ////delete掉3中字符串不可以拼接的部分
109             //此时s字符串为  "你好我们都是美女" 
110             //startPos + count 是1+3中可以拼接的字符串,即从"们"和"都"之间的位置开始,去掉"都是"这两个字符串
111             //startPos值为2,count值为2,startPos + middleString.length()即为"是"后面的位置,删除"都是"
112             if(Debug){
113                 Log.i(TAG, "before s.delete  temp="+temp);
114                 Log.i(TAG, "要删除的字符:"+s.subSequence(startPos + count, startPos + middleString.length()).toString());
115             }
116             Toast.makeText(this, "已超过最大字节数限制", Toast.LENGTH_SHORT).show();
117             s.delete(startPos + count, startPos + middleString.length());
118             if(Debug){
119                 Log.i(TAG, "afters s.delete  temp="+temp);
120                 Log.i(TAG, "before setText###########");
121             }
122             //当执行s.delete时,字符串发生变变,会再次执行beforeTextChanged、afterTextChanged这些方法,只有执行完afterTextChanged方法后
123             //才会执行s.delete后面的方法,即textview.setText("1 ...);
124             //再一次执行afterTextChanged方法时,由于字符串长度已经没有超长,故会执行else中的方法,然后打印11 name= ,打印完后
125             //会继续执行s.delete下面的after setText###########,,然后再次打印11 name=
126             //textview.setText("1、内容:"+temp+" 字符数:"+temp.length()+" 字节数:"+temp.getBytes().length);
127             textview.setText(s.toString().trim());
128             if(Debug){
129                 Log.i(TAG, "after setText###########");
130             }
131             
132         }else{
133             textview.setText("2、内容:"+name+" 字符数:"+name.length()+" 字节数:"+name.getBytes().length);
134         }
135         if(Debug){
136             Log.i(TAG, "11 name="+name);
137         }  
138     }
139 }

 

activity_main.xml文件,只有两个空间,一个textview用来显示当前edittext中的内容(处理后,未超出限制的内容),editext用来输入字符,汉字,英文都可以

 1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 2     xmlns:tools="http://schemas.android.com/tools"
 3     android:layout_width="match_parent"
 4     android:layout_height="match_parent"
 5     tools:context="${relativePackage}.${activityClass}" >
 6 
 7     <TextView
 8         android:id="@+id/tv"
 9         android:layout_width="wrap_content"
10         android:layout_height="wrap_content"
11         android:text="@string/hello_world" />
12 <EditText 
13     android:id="@+id/et"
14     android:layout_width="match_parent"
15     android:layout_height="wrap_content"
16     android:layout_below="@id/tv"/>
17 </RelativeLayout>

 

六、代码bug修复:

bug描述:  

    你好我们美女,中间插入"1234我来了",只能插入1,单独插入英文字母时时可以再插入2个英文字母

原因分析: 

    输入的字节数最大为20个字节,应该包括20字节。

代码修改:

    MainActivity.java代码第89行出应为

   if(sb.append(middleString.subSequence(i, i+1)).toString().getBytes().length <= MAX_LENGTH)

 
整理后的代码,去掉了log(建议编写代码时一定要加log、加注释)
 1 package com.example.textwatcher;
 2 
 3 import android.app.Activity;
 4 import android.os.Bundle;
 5 import android.text.Editable;
 6 import android.text.TextWatcher;
 7 import android.util.Log;
 8 import android.widget.EditText;
 9 import android.widget.TextView;
10 import android.widget.Toast;
11 
12 public class MainActivity extends Activity implements TextWatcher{
13 
14     private static final int MAX_LENGTH = 20;//最大字节数,不用区分是中文还是英文,字节数一定,可以动态插入字符个数(如:还可插入1个汉字,若是英文则还可以插入3个英文字母<手机显示一个汉字要3个字节,一个字母1个字节>),一般此值为255, 2^8 -1
15     private EditText edittext;
16     private TextView textview;
17     private String temp = null;//临时变量
18     private String name = null;//改变后的字符串
19     private String frontString = null;//frontString是字符串 1
20     private String middleString = null;//字符串3
21     private String behindString = null;//字符串2
22     private int editStart = 0;
23     private int editEnd = 0;
24     private int startPos = 0;//光标的位置,即1/2之间的位置
25     private int endPos = 0;//改变文字后光标的位置
26     @Override
27     protected void onCreate(Bundle savedInstanceState) {
28         super.onCreate(savedInstanceState);
29         setContentView(R.layout.activity_main);
30         edittext = (EditText) findViewById(R.id.et);
31         textview = (TextView) findViewById(R.id.tv);
32         edittext.addTextChangedListener(this);
33     }
34 
35     @Override
36     public void beforeTextChanged(CharSequence s, int start, int count,
37             int after) {
38         // TODO Auto-generated method stub
39         startPos = start;//在字符串改变前保存光标的位置,即1、2之间的位置
40         temp = s.toString();//保留字符串改变前的值 1+2、即4
41         frontString = s.subSequence(0, startPos).toString();//frontString是字符串 1
42     }
43 
44     @Override
45     public void onTextChanged(CharSequence s, int start, int before, int count) {
46         // TODO Auto-generated method stub
47 
48     }
49 
50     @Override
51     public void afterTextChanged(Editable s) {
52         // TODO Auto-generated method stub
53         //此count和 beforeTextChanged方法中的count没有任何联系 
54         int count = 0;//定义为局部变量,防止上次的值对其有影响(小编刚开始定义为了全局变量,结果引发的错误排查了很久)
55         name = s.toString().trim();//主要是为了获取name的字节长度,为了调试用  、即5
56         editEnd =  edittext.getSelectionEnd();
57         behindString = name.substring(editEnd, name.length());//behindString是字符串2
58         middleString = name.substring(startPos, editEnd);//middleString是字符串3
59         StringBuilder sb = new StringBuilder(temp);//根据改变前的字符串构键sb   
60         if(name.getBytes().length > MAX_LENGTH && middleString != null && middleString != ""){
61             for(int i = 0;i < middleString.length();i++){
62                 if(sb.append(middleString.subSequence(i, i+1)).toString().getBytes().length <= MAX_LENGTH){
63                     count = i + 1;
64                 }else{
65                     break;//如果if语句不成立,则直接跳出for循环
66                 }
67             }        
68             temp = new StringBuilder(frontString).append(middleString.substring(0, count)).append(behindString).toString();
69             Toast.makeText(this, "已超过最大字节数限制", Toast.LENGTH_SHORT).show();
70             s.delete(startPos + count, startPos + middleString.length());
71             textview.setText(s.toString().trim());        
72         }else{
73             textview.setText("2、内容:"+name+" 字符数:"+name.length()+" 字节数:"+name.getBytes().length);
74         }75     }
76 }

七、有任何疑问请留言,欢迎探讨与指正 ,QQ群238696947

转载请注明出处:http://www.cnblogs.com/wangqx/p/6096272.html

 

 

以上是关于EditText字符限制-字节数限制-一次截取超过限制部分的主要内容,如果未能解决你的问题,请参考以下文章

mysql varchar 最大可以设置多少

Android EditText输入字数限制总结(包含中文输入内存溢出的解决方法)

DataBufferLimitException:超过最大字节数限制以缓冲 webflux 错误

oracle限制字符串长度

Mysql使用CHAR或BLOB来存储具有已知字节大小限制的UTF-8字符串

Spring Cloud Hoxton.SR5 与 Eureka 和 WebFlux 的问题:超过了缓冲区的最大字节数限制