一个截取字符串函数引发的思考

背景

前些天,遇到这样一个问题,问题的内容如下:

要求编写一个截取字符串的函数,输入为一个字符串和字节数,输出为按字节截取的字符串。但是要保证汉字不被截半个,如“我ABC”, 4,截取后的效果应该为“我AB”,输入“我ABC汉DEF”, 6,应该输出为“我ABC”,而不是“我ABC+汉的半个”。

问题

刚看到这个问题的时候,以为还是很简单的,但写出来之后,发现并不是想要的效果。回想一下当时的思路,就发现刚开始思考的时候,就没有考虑好,而且把汉字会导致的问题给忽略了,就这样没有一个完整的思路,就直接开始写代码了。大家可想而知,写出来的效果当然不会是你想要的了。

既然题目中已经要求了汉字存在时应该出现什么样的结果,那么我们就应该考虑,如何把英文和中文都统一成一种编码,而不是对它们进行单独的处理。设想一下,如果程序中对它们进行单独的处理,那么会出现什么样的问题呢?这个稍后再说。

实现

遇到这些问题之后,总得想办法解决吧,于是在网上找到了一种解决方案,主旨是,统一中英文的编码方式,即在GBK的编码方式下,把要截取的字符串转换为字节数组,此时,一个汉字就会转换为两个负数,例如,“我”就会转换为“-50, -46”。然后再针对截取到的负数的个数进行处理,就可以把汉字的问题解决了。

截取函数代码

<span style="font-family:Microsoft YaHei;font-size:12px;">/**
 * 截取要点:
 * 1. 首先将字符串转换成字节数组,再将字节数组的每个元素拿出来,判断有无负数(一个汉字为两个负数),即可知道有没有汉字
 * 2. len:是将字符串转换成字节数组后,要截取的长度,如“我ABC你”的字节数组长度为7(-50,-46,65,66,67,-60,-29)
 * 		,而截取的是6(-50,-46,65,66,67,-60)
 * 3. 对截取的字节数组(-50,-46,65,66,67,-60),统计负数的个数
 * 4. String里的 substring 方法将双字节的汉字当成一个字节的字符(UCS2字符)
 *
 * @param str
 * @param len
 * @return
 */
public static String subString(String str, int len) {
	// 判断字符串是否为空
	if (str == null && "".equals(str)) {
		return null;
	}

	// 将字符串中的char数组转换成指定编码方式的byte数组的函数
	byte[] strBytes = null;

	try {
		strBytes = str.getBytes("GBK");
	} catch (UnsupportedEncodingException e) {
		e.printStackTrace();
	}

	// 得到字符串的长度
	int strLen = strBytes.length;
	// 判断截取字符串的长度是否在判断的范围内,否则返回原串
	if (len >= strLen || len < 1) {
		return str;
	}

	// 打印出字符串长度和截取的长度
	System.out.println("strBytes.length = " + strBytes.length);
	System.out.println("len = " + len);

	int count = 0;
	for (int i = 0; i < len; i++) {
		// 将每个字节数组转换为整型数,以为后面根据值的正负来判断是否为汉字
		int value = strBytes[i];
		// System.out.println("strBytes[" + i + "] = " + strBytes[i] + ",");
		System.out.println(value + ",");	// 我ABC你 -50,-46,65,66,67,-60,-29

		// 对于第一种情况:
		// 注,一个函数转换成整型书就为两个负整数,上面的“我ABC你”,转换成整型数就为 -50,-46,65,66,67,-60,-29
		// 但是 len=6,所以截取下来就是 -50,-46,65,66,67,-60,count就为3
		// 如果是汉字(负),则统计截取字符串中的汉字所占字节数
		if (value < 0) {
			count++;
		}

		System.out.println("汉字字节码的数量为 " + count);
	}

	// 依据判断给定的字符串是否含有汉字,利用String类的substring()方法来截取不同的长度
	// 根据所统计的字节数,判断截取到字符是否为半个汉字,奇数为半个汉字
	if (count % 2 != 0) {
		// 如果在截取长度为1时,则将该汉字取出,其他情况则不截取(截取字节长度数 - 截取汉字字节数/2 - 截取到的半个汉字的字节数)
		len = (len == 1) ? len : len - count / 2 - 1;	// len=6-3/2-1=4 我ABC
		// System.out.println("count / 2 = " + count / 2);
		System.out.println("处理后的len = " + len);
	} else {
		// 截取字符长度为字节长度 - 汉字所占字节长度 / 2 (汉字占两个字节)
		len = len - (count / 2);
	}

	return str.substring(0, len);
}</span>

测试代码

<span style="font-family:Microsoft YaHei;font-size:12px;">/**
 * @param args
 */
public static void main(String[] args) {
	// 情况一
	System.out.println("------------ 情况一  ------------");
	String inStr = "我ABC你";
	String str = subString(inStr, 6);
	System.out.println(str);	// 我ABC

	// 情况二
	System.out.println("------------ 情况二  ------------");
	inStr = "我ABC汉DEF";
	str = subString(inStr, 1);
	System.out.println(str);	// 我

	// 情况三
	System.out.println("------------ 情况三  ------------");
	inStr = "我AB爱孩子CDEF";
	str = subString(inStr, 9);
	System.out.println(str);	// 我AB爱孩

	// 情况四
	System.out.println("------------ 情况四  ------------");
	inStr = "ABCDEF";
	str = subString(inStr, 4);
	System.out.println(str); 	// ABCD
}</span>

测试结果

思考

通过这个题目,给了我很多的启示,首先,在“下笔”之时,就应该考虑到灵活性的问题,虽然这里只是中英文的字符串截取,但是如果再增加一种其他语言呢?扩展性就没有那么好了,这也是上边所提到的问题。好的设计是一方面,代码的实现上,也要做到解耦合。同时,这也提醒了我,在考虑问题的时候,首先不能一头扎到细节中,而是先要有一个全局观,对整体有个全面的了解,将具体的问题抽象化、简单化,层层剖析;做完这一点之后,才是对具体的问题具体分析。

一个截取字符串函数引发的思考,布布扣,bubuko.com

时间: 2025-01-15 23:00:56

一个截取字符串函数引发的思考的相关文章

一个数据交换函数引发的思考

近日,在书中看到一个关于数据交换函数的源代码,发现挺有意思,具体代码如下: 1 void swap(int* a, int* b) 2 { 3 *a ^= *b ^= *a ^= *b; 4 } 根据 C 语言异或赋值操作符(^=)的计算规则和异或运算符(^)的运算法则,应按照从右到左的顺序进行计算,具体计算过程演示如下: 1 *a = *a ^ *b; 2 *b = *b ^ *a = *b ^ ( *a ^ *b ) = *a; //将式1代入 3 *a = *a ^ *b = ( *a ^

面试题之java 编写一个截取字符串的函数,输入为一个字符串和字节数,输出为按字节截取的字符串。 要求不能出现截半的情况

题目:10. 编写一个截取字符串的函数,输入为一个字符串和字节数,输出为按字节截取的字符串. 但是要保证汉字不被截半个,如“我ABC”4,应该截为“我AB”,输入“我ABC汉DEF”,6,应该输出为“我ABC”而不是“我ABC+汉的半个”. 一.需要分析 1.输入为一个字符串和字节数,输出为按字节截取的字符串-------------->按照字节[byte]截取操作字符串,先将String转换成byte类型 .2.汉字不可以截半----------------------------------

使用JS截取字符串函数详解

使用JS截取字符串函数详解 JS截取字符串函数:一.函数:split();二.函数:John();三.函 数:indexOf();四.其他几种方 法:stringObject.substring(start,stop);stringObject.substr(start [, length ])... 一.函数:split() 功能:使用一个指定的分隔符把一个字符串分割存储到数组 例子: str=”jpg|bmp|gif|ico|png”; arr=theString.split(”|”); /

PHP截取字符串函数substr()函数实例用法详解

在PHP中有一项非常重要的技术,就是截取指定字符串中指定长度的字符.PHP对于字符串截取可以使用PHP预定义函数substr()函数来实现.下面就来介绍一下substr()函数的语法及其应用. substr()函数语法格式如下:大理石平台厂家 1 substr(string, start, length); substr()函数参数说明如下: 参 数 说 明 string 指定字符串对象 start 指定开始截取字符串的位置.如果参数start为负数,则从字符串的末尾开始截取 length 可选

thinkphp内置截取字符串函数无法显示省略号解决方法

thinkphp内置截取字符串函数无法显示省略号解决方法 functions.php function msubstr($str, $start=0, $length, $charset="utf-8", $suffix=true){ if(function_exists("mb_substr")) {      if($suffix)    {         if($str==mb_substr($str, $start, $length, $charset))

JS简单应用之截取字符串函数以及replace,split函数

JS截取字符串:slice(),substring()和substr()1.substr 方法返回一个从指定位置开始的指定长度的子字符串.stringvar.substr(start [, length ])参数stringvar必选项.要提取子字符串的字符串文字或 String 对象.start必选项.所需的子字符串的起始位置.字符串中的第一个字符的索引为 0.length可选项.在返回的子字符串中应包括的字符个数.说明如果 length 为 0 或负数,将返回一个空字符串.如果没有指定该参数

java截取字符串函数

substring public String substring(int beginIndex)返回一个新的字符串,它是此字符串的一个子字符串.该子字符串始于指定索引处的字符,一直到此字符串末尾. 例如: "unhappy".substring(2) returns "happy" "Harbison".substring(3) returns "bison" "emptiness".substring(

数据库截取字符串函数

MySQL数据库和SQL Server数据库的字符串截取函数比较 MySQL字符串截取函数:SUBSTR(String string,num start,num length) string是原字符串, start是起始位置(从1开始), length是截取字符串的长度: SQL Server字符串截取函数:SUBSTRING(String string,num start,num length) string是原字符串, start是起始位置(从1开始), length是截取字符串的长度: 除

JS截取字符串函数详解

一.函数:split() 功能:使用一个指定的分隔符把一个字符串分割存储到数组 例子: str="jpg|bmp|gif|ico|png"; arr=theString.split("|"); //arr是一个包含字符值"jpg"."bmp"."gif"."ico"和"png"的数组 二.函数:John() 功能:使用您选择的分隔符将一个数组合并为一个字符串 例子: