替换字节数组中某些字节的最佳方法是什么??
例如,我有
bytesFromServer = listener.Receive(ref groupEP);
,我可以 BitConverter.ToString(bytesFromServer)
将其转换为可读格式,以返回类似 的内容
48 65 6c 6c 6f 20
74 68 65 72 65 20
68 65 6c 70 66 75
6c 20 70 65 6f 70
6c 65
我想将其中的“68 65 6c”替换为“68 00 00”之类的内容(仅作为示例)。 byte[] 上没有 .Replace()。
有没有一种简单的方法可以将其转换回 byte[]?
任何帮助表示赞赏。谢谢!
你可以对其进行编程....开始尝试...但是,这还不够健壮,还没有像代码那样的生产...注意差一错误,我没有完全测试这一点...
public int FindBytes(byte[] src, byte[] find)
{
int index = -1;
int matchIndex = 0;
// handle the complete source array
for(int i=0; i<src.Length; i++)
{
if(src[i] == find[matchIndex])
{
if (matchIndex==(find.Length-1))
{
index = i - matchIndex;
break;
}
matchIndex++;
}
else if (src[i] == find[0])
{
matchIndex = 1;
}
else
{
matchIndex = 0;
}
}
return index;
}
public byte[] ReplaceBytes(byte[] src, byte[] search, byte[] repl)
{
byte[] dst = null;
int index = FindBytes(src, search);
if (index>=0)
{
dst = new byte[src.Length - search.Length + repl.Length];
// before found array
Buffer.BlockCopy(src,0,dst,0, index);
// repl copy
Buffer.BlockCopy(repl,0,dst,index,repl.Length);
// rest of src array
Buffer.BlockCopy(
src,
index+search.Length ,
dst,
index+repl.Length,
src.Length-(index+search.Length));
}
return dst;
}
作为扩展方法实现
public void Replace(this byte[] src, byte[] search, byte[] repl)
{
ReplaceBytes(src, search, repl);
}
正常使用方法:
ReplaceBytes(bytesfromServer,
new byte[] {0x75, 0x83 } ,
new byte[]{ 0x68, 0x65, 0x6c});
扩展方法用法:
bytesfromServer.Replace(
new byte[] {0x75, 0x83 },
new byte[]{ 0x68, 0x65, 0x6c});
改进 rene 的代码,我为它创建了一个 while 循环来替换所有出现的情况:
public static byte[] ReplaceBytes(byte[] src, byte[] search, byte[] repl)
{
byte[] dst = null;
byte[] temp = null;
int index = FindBytes(src, search);
while (index >= 0)
{
if (temp == null)
temp = src;
else
temp = dst;
dst = new byte[temp.Length - search.Length + repl.Length];
// before found array
Buffer.BlockCopy(temp, 0, dst, 0, index);
// repl copy
Buffer.BlockCopy(repl, 0, dst, index, repl.Length);
// rest of src array
Buffer.BlockCopy(
temp,
index + search.Length,
dst,
index + repl.Length,
temp.Length - (index + search.Length));
index = FindBytes(dst, search);
}
return dst;
}
此方法可行,但如果源字节太大,我更喜欢使用“窗口”函数来逐块处理字节。否则会占用大量内存。
不幸的是,所有帖子都存在问题(正如评论中已经指出的那样)。 另一个问题
有正确答案我自己需要一个解决方案,并编写了以下代码。这在使用可枚举和多个搜索替换术语时也更加灵活。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
public class ByteTools
{
static void ByteReplaceTests()
{
var examples = new(string source, string search, string replace)[]
{
("bababanana", "babanana", "apple"),
("hello guys", "hello", "hello world"),
("apple", "peach", "pear"),
("aaaa", "a", "abc"),
("pear", "pear", ""),
("good morning world", "morning", "morning"),
("ababab", "ab", "ababab"),
("ababab", "abab", "ab"),
("", "aa", "bb"),
};
int i = 0;
foreach (var (source, search, replace) in examples)
{
var stringReplaceResults = source.Replace(search, replace);
var sourceByte = Encoding.ASCII.GetBytes(source);
var searchByte = Encoding.ASCII.GetBytes(search);
var replaceByte = Encoding.ASCII.GetBytes(replace);
//converts string values to bytes, does the replace, then converts back to string
var byteReplaceResults = Encoding.ASCII.GetString(
ByteReplace(sourceByte, (searchByte, replaceByte)).ToArray());
Console.WriteLine($"{i}: {source}, {search}, {replace}");
Console.WriteLine($" String.Replace() => {stringReplaceResults}");
Console.WriteLine($" BytesReplace() => {byteReplaceResults}");
i++;
}
}
static IEnumerable<byte> ByteReplace(IEnumerable<byte> source, params (byte[] search, byte[] replace)[] replacements)
{
if (source == null)
throw new ArgumentNullException(nameof(source));
if (replacements == null)
throw new ArgumentNullException(nameof(replacements));
if (replacements.Any(r => r.search == null || r.search.Length == 0))
throw new ArgumentOutOfRangeException(nameof(replacements), "Search parameter cannot be null or empty");
if (replacements.Any(r => r.replace == null))
throw new ArgumentOutOfRangeException(nameof(replacements), "Replace parameter cannot be null");
var maxMatchSize = replacements.Select(r => r.search.Length).Max();
var bufferSize = maxMatchSize * 2;
var buffer = new byte[bufferSize];
int bufferStart = 0;
int bufferPosition = 0;
byte[] nextBytes()
{
foreach ((byte[] search, byte[] replace) in replacements)
{
if (ByteStartsWith(buffer, bufferStart, bufferPosition - bufferStart, search))
{
bufferStart += search.Length;
return replace;
}
}
var returnBytes = new byte[] { buffer[bufferStart] };
bufferStart++;
return returnBytes;
}
foreach (var dataByte in source)
{
buffer[bufferPosition] = dataByte;
bufferPosition++;
if (bufferPosition - bufferStart >= maxMatchSize)
{
foreach (var resultByte in nextBytes())
yield return resultByte;
}
if (bufferPosition == bufferSize - 1)
{
Buffer.BlockCopy(buffer, bufferStart, buffer, 0, bufferPosition - bufferStart);
bufferPosition -= bufferStart;
bufferStart = 0;
}
}
while (bufferStart < bufferPosition)
{
foreach (var resultByte in nextBytes())
yield return resultByte;
}
}
static bool ByteStartsWith(byte[] data, int dataOffset, int dataLength, byte[] startsWith)
{
if (data == null)
throw new ArgumentNullException(nameof(data));
if (startsWith == null)
throw new ArgumentNullException(nameof(startsWith));
if (dataLength < startsWith.Length)
return false;
for (int i = 0; i < startsWith.Length; i++)
{
if (data[i + dataOffset] != startsWith[i])
return false;
}
return true;
}
}
public static byte[] ReplaceBytes(byte[] src, byte[] search, byte[] repl)
{
if (repl == null) return src;
int index = FindBytes(src, search);
if (index < 0) return src;
byte[] dst = new byte[src.Length - search.Length + repl.Length];
Buffer.BlockCopy(src, 0, dst, 0, index);
Buffer.BlockCopy(repl, 0, dst, index, repl.Length);
Buffer.BlockCopy(src, index + search.Length, dst, index + repl.Length,src.Length - (index + search.Length));
return dst;
}
public static int FindBytes(byte[] src, byte[] find)
{
if(src==null|| find==null|| src.Length==0|| find.Length == 0 || find.Length> src.Length) return -1;
for (int i = 0; i < src.Length - find.Length +1 ; i++)
{
if (src[i] == find[0])
{
for(int m=1;m< find.Length;m++)
{
if (src[i + m] != find[m]) break;
if (m == find.Length - 1) return i;
}
}
}
return -1;
}
这可能是一个好方法,我已经在很多代码中进行了测试。
我拼凑起来的东西......很快就要测试它。来自如何将字节数组转换为十六进制字符串,反之亦然?
public byte[] ReplaceBytes(byte[] src, string replace, string replacewith)
{
string hex = BitConverter.ToString(src);
hex = hex.Replace("-", "");
hex = hex.Replace(replace, replacewith);
int NumberChars = hex.Length;
byte[] bytes = new byte[NumberChars / 2];
for (int i = 0; i < NumberChars; i += 2)
bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
return bytes;
}
如果要替换所有出现的情况,可以使用以下代码:
using System;
class Program
{
static void ReplaceAll(byte[] source, byte[] oldBytes, byte[] newBytes)
{
for (int i = 0; i < source.Length - oldBytes.Length + 1; i++)
{
bool match = true;
for (int j = 0; j < oldBytes.Length; j++)
{
if (source[i + j] != oldBytes[j])
{
match = false;
break;
}
}
if (match)
{
Array.Copy(newBytes, 0, source, i, newBytes.Length);
}
}
}
static void Main()
{
byte[] original = {90, 97, 99, 97, 98, 99}; // original byte array
byte[] oldBytes = {97, 98, 99}; // old byte array to be replaced
byte[] newBytes = {100, 101, 102}; // new byte array to replace with
ReplaceAll(original, oldBytes, newBytes);
Console.WriteLine(BitConverter.ToString(original));
}
}
如果您正在寻找一个简短而快速的解决方案来进行等长替换(如原始问题中的要求),请尝试以下操作:
var index = arr.AsSpan().IndexOf(replaceFrom);
if (index >= 0)
Array.copy(replaceTo, 0, arr, index, replaceTo.length)
希望对某人有帮助!