短信切割算法
在一个项目中,要用到手机发送短信,但是使用的短信猫却无法支持大于70个字符的情况,而且经常收到有朋友的短信,比较长的手机都会自动将它切成几个短信发送。有时候很搞,收到的短信有两条,第二条就只有一个句号而已。或者几乎这种手机都不会去理解语义,直接就在70个字符处切割。
private const String PRE_STR = "(续)";
private const String SUF_STR = "(待续)";
private static int PRE_STR_LEN = PRE_STR.Length;
private static int SUF_STR_LEN = SUF_STR.Length;
private static int EXT_LENGTH = PRE_STR_LEN + SUF_STR_LEN;
private static int MAX_LEN = 70; //每个短信最长大小
/// <summary>
/// 切割字符串,使每串不超过70个字符
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
private List<String> StringSplit(String str)
{
List<String> msms = new List<string>();
bool star = true;
while (true)
{
if (!star)
{
str = PRE_STR + str;
}
int lenght = str.Length;
int msgCoun = getMsgCount(lenght);
int nullSpace = getLastMsgLeftCount(lenght, msgCoun);
if (str.Length <= MAX_LEN)
{
//不用分割
msms.Add(str);
break;
}
else
{
int splitIndex = getSplitIndex(str, nullSpace);
string tempStr = str.Substring(0, splitIndex);
msms.Add(tempStr + String SUF_STR);
str = str.Substring(splitIndex);
}
star = false;
}
return msms;
}
/// <summary>
/// 获取一条短信最小可以分多少条短信
/// </summary>
/// <param name="t">短信长度</param>
/// <returns></returns>
private int getMsgCount(int t)
{
if (t < MAX_LEN)
return 1;
int n = (int)((t + MAX_LEN - 2 * EXT_LENGTH - 1) / (MAX_LEN - EXT_LENGTH));
return n;
}
/// <summary>
/// 计算最后一条信息还可添加多少个字符
/// </summary>
/// <param name="t">短信总字符数</param>
/// <param name="n">短信理想情况分页数</param>
/// <returns></returns>
private int getLastMsgLeftCount(int t,int n)
{
if (t <= MAX_LEN)
return MAX_LEN - t;
int l = MAX_LEN + (MAX_LEN - EXT_LENGTH) * (n - 1) - t;
return l;
}
private static char[] splitChar = new char[] { ',',' ','.',';','!',')','>','}',']',',',' ','。',';','!',')','》','"n','"t'};
/// <summary>
/// 比较智能地去判断分割的位置,尽量在有分隔符的地方分割
/// </summary>
/// <param name="str">str的长度一定大于MAX_LEN</param>
/// <param name="space">剩余可用空间大小</param>
/// <returns></returns>
private int getSplitIndex(String str,int space)
{
if (space > 0)
{
for (int i = MAX_LEN - SUF_STR_LEN - 1, d = (MAX_LEN - SUF_STR_LEN - space - 1); i >= d; --i)
{
foreach (char c in splitChar)
{
if (str[i] == c)
{
//匹配
Console.WriteLine(i + 1);
return i + 1;
}
}
}
}
return MAX_LEN - SUF_STR_LEN;
}
public static void Main(String[] args)
{
string str = "如果短信的长度超过70个字符,程序就会自动根据短信中的分隔符进行分割,在不是非常苛刻的情况下,它不会将一个词分成两段来发,比如,不会出现""你好""的前一个字在第一条短信内,而""好""字在第二条短信内!这都是在不增加短信数量的情况下优化的!";
List<String> ms = new MobileRegistService().StringSplit(str);
foreach (String m in ms)
{
Console.WriteLine(m + "==>" + m.Length);
}
}
要做到完全理解语义也不大可能,但是突然想到,为什么不可以根据分隔符去切割呢?至少这样子不会把一段完整的内容不会被强行分割出来。
比如有下面一段话:
如果短信的长度超过70个字符,程序就会自动根据短信中的分隔符进行分割,在不是非常苛刻的情况下,它不会将一个词分成两段来发,比如,不会出现"你好"的前一个字在第一条短信内,而"好"字在第二条短信内!这都是在不增加短信数量的情况下优化的!
普通的短信会分成:
1. 如果短信的长度超过70个字符,程序就会自动根据短信中的分隔符进行分割,在不是非常苛刻的情况下,它不会将一个词分成两段来发,比如,不会出现"你(70个字符)
2.好"的前一个字在第一条短信内,而"好"字在第二条短信内!这都是在不增加短信数量的情况下优化的!(47个字符)
使用下面的程序,可以得到以下的另一种分法:
1.如果短信的长度超过70个字符,程序就会自动根据短信中的分隔符进行分割,在不是非常苛刻的情况下,它不会将一个词分成两段来发,比如,(待续)==>68
2.(续)不会出现"你好"的前一个字在第一条短信内,而"好"字在第二条短信内!这都是在不增加短信数量的情况下优化的!==>56
很显然,第二种情况才是比较人性化一点的。看看程序吧:
private const String PRE_STR = "(续)";
private const String SUF_STR = "(待续)";
private static int PRE_STR_LEN = PRE_STR.Length;
private static int SUF_STR_LEN = SUF_STR.Length;
private static int EXT_LENGTH = PRE_STR_LEN + SUF_STR_LEN;
private static int MAX_LEN = 70; //每个短信最长大小
/// <summary>
/// 切割字符串,使每串不超过70个字符
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
private List<String> StringSplit(String str)
{
List<String> msms = new List<string>();
bool star = true;
while (true)
{
if (!star)
{
str = PRE_STR + str;
}
int lenght = str.Length;
int msgCoun = getMsgCount(lenght);
int nullSpace = getLastMsgLeftCount(lenght, msgCoun);
if (str.Length <= MAX_LEN)
{
//不用分割
msms.Add(str);
break;
}
else
{
int splitIndex = getSplitIndex(str, nullSpace);
string tempStr = str.Substring(0, splitIndex);
msms.Add(tempStr + String SUF_STR);
str = str.Substring(splitIndex);
}
star = false;
}
return msms;
}
/// <summary>
/// 获取一条短信最小可以分多少条短信
/// </summary>
/// <param name="t">短信长度</param>
/// <returns></returns>
private int getMsgCount(int t)
{
if (t < MAX_LEN)
return 1;
int n = (int)((t + MAX_LEN - 2 * EXT_LENGTH - 1) / (MAX_LEN - EXT_LENGTH));
return n;
}
/// <summary>
/// 计算最后一条信息还可添加多少个字符
/// </summary>
/// <param name="t">短信总字符数</param>
/// <param name="n">短信理想情况分页数</param>
/// <returns></returns>
private int getLastMsgLeftCount(int t,int n)
{
if (t <= MAX_LEN)
return MAX_LEN - t;
int l = MAX_LEN + (MAX_LEN - EXT_LENGTH) * (n - 1) - t;
return l;
}
private static char[] splitChar = new char[] { ',',' ','.',';','!',')','>','}',']',',',' ','。',';','!',')','》','"n','"t'};
/// <summary>
/// 比较智能地去判断分割的位置,尽量在有分隔符的地方分割
/// </summary>
/// <param name="str">str的长度一定大于MAX_LEN</param>
/// <param name="space">剩余可用空间大小</param>
/// <returns></returns>
private int getSplitIndex(String str,int space)
{
if (space > 0)
{
for (int i = MAX_LEN - SUF_STR_LEN - 1, d = (MAX_LEN - SUF_STR_LEN - space - 1); i >= d; --i)
{
foreach (char c in splitChar)
{
if (str[i] == c)
{
//匹配
Console.WriteLine(i + 1);
return i + 1;
}
}
}
}
return MAX_LEN - SUF_STR_LEN;
}
public static void Main(String[] args)
{
string str = "如果短信的长度超过70个字符,程序就会自动根据短信中的分隔符进行分割,在不是非常苛刻的情况下,它不会将一个词分成两段来发,比如,不会出现""你好""的前一个字在第一条短信内,而""好""字在第二条短信内!这都是在不增加短信数量的情况下优化的!";
List<String> ms = new MobileRegistService().StringSplit(str);
foreach (String m in ms)
{
Console.WriteLine(m + "==>" + m.Length);
}
}
程序很简单,就不多说了,主要就是根据一些分隔符去分割。