截取指定长度字节数后的字符串,多余部分用“…”

本文介绍了一个实用的字符串处理方法,能够根据指定长度截断字符串,并使用省略号替换超出部分,适用于各种需要限制文本显示长度的场景。

/**

  • 返回截取指定长度字节数后的字符串,多余部分用“…”代替
  • @作者 jiyanle
  • @日期 2014-7-6
  • @param strs
  • @param length
  • @return
    */
    public static String cutStr(String strs, int length) {
    int sum = 0;
    String finalStr = “”;
    if (null == strs || strs.getBytes(“UTF-8”).length <= length) {
    finalStr = (strs==null?"":strs);
    } else {
    for (int i = 0; i < strs.length(); i++) {
    String str = strs.substring(i, i + 1);
    // 累加单个字符字节数
    sum += str.getBytes(“UTF-8”).length;
    if (sum > length) {
    finalStr = strs.substring(0, i) + “…”;
    break;
    }
    }
    }
    return finalStr;
    }
<think>好的,我现在需要帮助用户解决将西门子PLC通讯获取的字节数组转换为字符串的问题,使用C#实现。首先,我需要回顾用户提供的引用内容,特别是引用[1]中的WriteWString方法,因为那里详细描述了如何将字符串写入字节数组。这应该对反向操作(即字节数组转字符串)有帮助。 根据引用[1],西门子的WSTRING格式在字节数组中的结构是:前两个字节是最大长度(WORD),接下来两个字节是实际长度(WORD),然后是Unicode编码的字符数据。每个字符占两个字节。因此,转换时需要先读取这两个长度值,但实际使用中可能只需要实际长度来确定有效字符数。 不过,用户可能从PLC读取到的字节数组可能包含这两个长度信息,或者可能已经处理过,直接包含字符数据。需要明确字节数组的结构。假设用户获取的字节数组是按照西门子WSTRING格式存储的,那么转换步骤如下: 1. 解析前4个字节,即最大长度和实际长度。每个WORD是两个字节,高位在前(大端序)。 2. 根据实际长度确定需要处理的字符数量。 3. 从第5个字节开始,每两个字节组成一个Unicode字符,转换为对应的字符。 4. 使用Encoding.Unicode来将字节数组转换为字符串,但需要注意字节序是否符合C#的默认小端序。西门子的数据可能是大端序,可能需要调整字节顺序。 例如,引用[1]中写入时,每个字符的高字节在前,低字节在后。而C#的Encoding.Unicode默认是小端序(低字节在前)。因此,转换时需要交换每个字符的两个字节,或者使用Encoding.BigEndianUnicode。 验证这一点:在写入时,字符的高字节放在前面,比如字符的ushort值被分解为高字节和低字节,依次存入buffer。因此,读取时,每个字符的两个字节是高字节在前,低字节在后,对应BigEndian编码。因此,在转换时应使用Encoding.BigEndianUnicode.GetString(),但需要从第4个字节之后开始处理字符部分。 但是,如果字节数组的结构没有包含前面的最大长度和实际长度,或者用户已经处理了这些部分,需要明确用户实际获得的字节数组的结构。例如,如果用户已经读取了DB块中的数据,那么整个字节数组可能包含前4个字节的长度信息,然后是字符数据。因此,转换时需要跳过前4个字节,然后处理后面的字符数据。 假设字节数组的结构是完整的WSTRING格式,包括最大长度和实际长度,那么转换代码的大致步骤是: - 读取前两个字节作为最大长度(可能不需要使用)。 - 读取接下来的两个字节作为实际字符数。 - 从索引4开始,每两个字节作为一个字符,使用BigEndianUnicode解码。 - 根据实际字符数截取字符,避免处理多余的字节。 但根据引用[1]中的写入代码,实际长度和最大长度都被设置为value.Length,即写入时实际长度等于最大长度,这可能是因为西门子的WSTRING需要预先指定最大长度,实际长度不能超过最大长度。因此,在读取时,实际长度可能等于或小于最大长度,但用户需要根据实际长度截取有效字符。 但实际应用中,西门子的WSTRING的实际长度可能存储在第二个WORD中,因此需要先解析这两个WORD的值。例如,前两个字节是最大长度,接下来的两个字节是实际长度。例如: byte[] bytes = ...; // 从PLC读取的字节数组 ushort maxLength = (ushort)((bytes[0] << 8) | bytes[1]); ushort actualLength = (ushort)((bytes[2] << 8) | bytes[3]); 然后字符数据从索引4开始,共actualLength * 2字节。因此,需要从bytes中提取从索引4开始的actualLength * 2个字节,然后将这些字节转换为字符串。 但需要考虑字节序:每个字符的两个字节是高字节在前,而C#的Encoding.BigEndianUnicode正是处理这种情况的,因为BigEndian的编码是高字节在前。因此,正确的做法是将这部分字节数组(从索引4开始,长度actualLength * 2)用Encoding.BigEndianUnicode.GetString()转换为字符串。 因此,代码的大致步骤: public static string BytesToWString(byte[] bytes) { if (bytes.Length < 4) throw new ArgumentException("字节数长度不足"); // 解析最大长度和实际长度 ushort maxLength = (ushort)((bytes[0] << 8) | bytes[1]); ushort actualLength = (ushort)((bytes[2] << 8) | bytes[3]); // 计算字符数据起始索引和长度 int dataStart = 4; int dataLength = actualLength * 2; if (bytes.Length < dataStart + dataLength) throw new ArgumentException("字节数长度不足"); // 提取字符数据部分 byte[] stringBytes = new byte[dataLength]; Array.Copy(bytes, dataStart, stringBytes, 0, dataLength); // 使用BigEndianUnicode解码 return Encoding.BigEndianUnicode.GetString(stringBytes); } 但需要注意,是否实际长度可能超过字节数组剩余部分长度,因此需要进行检查。另外,可能用户读取的字节数组是否已经去除了前四个字节的长度信息?如果用户直接读取的是字符串数据部分,那么可能不需要处理前四个字节,这时候需要直接转换。但根据引用[1],写入时是包含了这四个字节的,因此读取时也应该包含这四个字节,所以上述方法是正确的。 此外,如果用户读取的字节数组不是WSTRING格式,而是普通的STRING(比如西门子的STRING类型,每个字符是ASCII或ANSI编码),处理方式会不同。但根据用户的问题,明确提到是宽字符串(WSTRING),所以应该用上述方法。 另外,引用[2]和[3]提到了使用Sharp7库进行数据读写,可能需要结合Sharp7的方法来读取字节数组。例如,用户可能使用S7.GetBytesAt()来获取字节数组,然后进行转换。但用户的问题核心是如何将已获取的字节数组转换为字符串,因此主要关注转换逻辑。 总结步骤: 1. 解析前4字节获取最大长度和实际长度。 2. 提取字符数据部分。 3. 使用BigEndianUnicode编码转换字节数组为字符串。 4. 处理可能的异常情况,如数组长度不足。 此外,可能需要测试不同的情况,例如空字符串或非WSTRING数据的情况,确保代码的健壮性。 最后,生成相关问题,例如关于编码方式、处理其他数据类型、性能优化等。</think>要将通过西门子通讯获取的字节数组转换为$WSTRING$字符串,需根据西门子宽字符串的存储规则解析数据。以下是分步实现方法: --- ### **步骤分析** 1. **数据结构解析** 西门子$WSTRING$的字节数组结构为: - 前2字节:最大长度(字) - 后2字节:实际长度(字) - 后续字节:Unicode字符数据(每个字符占2字节,大端序)[^1] 2. **字节序处理** Unicode字符存储采用大端序(高字节在前),需使用`Encoding.BigEndianUnicode`解码。 --- ### **C#实现代码** ```csharp using System.Text; public static string ConvertBytesToWString(byte[] bytes) { if (bytes == null || bytes.Length < 4) throw new ArgumentException("无效的字节数组"); // 解析最大长度和实际长度(大端序) ushort maxLength = (ushort)((bytes[0] << 8) | bytes[1]); ushort actualLength = (ushort)((bytes[2] << 8) | bytes[3]); // 计算字符数据起始位置和长度 int dataStartIndex = 4; int dataByteLength = actualLength * 2; if (bytes.Length < dataStartIndex + dataByteLength) throw new ArgumentException("字节数长度不足"); // 提取字符数据部分 byte[] stringBytes = new byte[dataByteLength]; Array.Copy(bytes, dataStartIndex, stringBytes, 0, dataByteLength); // 解码为大端序Unicode字符串 return Encoding.BigEndianUnicode.GetString(stringBytes); } ``` --- ### **代码说明** - **长度解析** 前4字节分别表示最大长度和实际长度,需按大端序组合为`ushort`类型。 - **字符数据提取** 从第5字节开始提取实际字符数据,长度为`实际长度 * 2`(每个字符2字节)。 - **解码方式** `Encoding.BigEndianUnicode`用于处理高字节在前的Unicode编码,与西门子PLC存储方式一致[^1]。 --- ### **示例调用** ```csharp // 假设从PLC读取的字节数组(示例数据:"AB") byte[] plcBytes = new byte[] { 0x00, 0x02, // 最大长度=2 0x00, 0x02, // 实际长度=2 0x00, 0x41, // 'A'的Unicode大端序 0x00, 0x42 // 'B'的Unicode大端序 }; string result = ConvertBytesToWString(plcBytes); // 输出"AB" ``` --- ### **异常处理建议** -字符串需检查`actualLength`是否为0。 -字节数组不含长度头,直接截取有效部分解码(需确认PLC数据类型)。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值