解析表示具有不同大小字段的 'fixed-length' 消息的 C# 字符串
Parsing C# string representing a 'fixed-length' message with fields of different sizes
我在 a 中有一个固定长度的字符串消息,如下所示:
"[=11=][=11=][=11=]j[=11=][=11=][=11=]\vT3A1111 2999BOSH 2100021 399APV 2100022 "
此消息是我将字节 [] 读入 StringBuilder 以构建字符串而创建的。
上面,字符串部分“[=16=][=16=][=16=]j[=16=][=16=][=16=]\v
”应该是LENGTH和ID字段,都是4字节长。但是,我不确定如何提取这 2 个值,但我可以看到 HEX 0j
是 106(1+1+8+9+30+9+9+30+9=106 总长度)。我不确定为什么 "v" 不是上面的“0v”,但我知道它应该是代表消息 ID 的十六进制值。
前 2 个长度为 4 的字段是 HEX,其他都是 ASCII。
这不是 EDI 消息(因此不能使用 EDI 解析器库)并且与具有某种字段标识符的 EDI 消息不同,我只有字节流并且我只知道字段的长度。这些字段是:
4 byte long message length ("[=12=][=12=][=12=]j")
4 byte long message id ("[=12=][=12=][=12=]\v")
1 byte long message type ("T")
1 byte long message sequence ("3")
8 byte long car Id ("A1111 ")
9 byte long part-1 price (" 2999")
30 byte long part-1 manufacturer ("BOSH ")
9 byte long part# ("2100021 ")
9 byte long part-2 price (" 399")
30 byte long part-2 manufacturer ("APV ")
9 byte long part# ("2100022 ")
所以,上面我有 2 个零件由 2 个制造商制造,但在实际示例中,它可能不仅仅是 2 个:
Part 1, 29.99, made by Bosh, part# 2100021
Part 2, 3.99, made by APV, part# 2100022
我想将所有价格和制造商字段从这个平面文件字符串中提取到 Part 所在的列表对象中
class Part
{
public decimal Price {get; set}
public string Manufacturer {get; set;}
public string PartNumber {get; set;}
}
因此,我的列表将包含所有零件及其价格和制造商。
因为我知道每个字段的长度,所以我知道我可以循环遍历这个字符串并获取与零件相关的数据。但是,我想知道是否有更优雅、更简单的方法来做到这一点。
或者更好的是,是否有一个开源库允许我解析这样的东西?
我用这种方法收到这条消息
private TcpClient clientSocket;
private NetworkStream serverStream;
private async System.Threading.Tasks.Task ReadResponseAsync()
{
if (serverStream.CanRead)
{
byte[] readBuffer = new byte[1024];
StringBuilder receivedMessage = new StringBuilder();
int readSoFar = 0;
do
{
readSoFar = await serverStream.ReadAsync(readBuffer, 0, readBuffer.Length);
receivedMessage.AppendFormat("{0}", Encoding.ASCII.GetString(readBuffer, 0, readSoFar));
}
while (serverStream.DataAvailable);
string msg = receivedMessage.ToString();
}
else
{
Log("Error", "Cannot read from NetworkStream");
}
}
@Enigmativity - 我尝试在 LinqPad 中发布你的答案并运行它(从未使用过它,只是下载并安装了它)但我没有看到你在你的帖子中发布的类似 table 的结构回答。你是怎么得到的?
这是我得到的
你说"byte[] into a StringBuilder to build string",所以我认为你有一个字符串。也许尝试使用 SubString(..),类似于:
var length = int.Parse(message.SubString(0,4);
var id = int.Parse(message.SubString(4,4);
等等
编辑:如果有不需要的填充字符,请尝试
message.Replace('-', ' ');
不优雅,但它会工作。
也许试试这样的方法:
void Main()
{
var line = "00580011T3A1111 2999Bosh 399APV 2399MAG ";
var lengths = new[] { 4, 4, 1, 1, 8, 9, 30, 9, 30, 9, 30 };
var starts = lengths.Aggregate(new[] { 0 }.ToList(), (a, x) => { a.Add(a.Last() + x); return a; });
var fields = starts.Zip(lengths, (p, l) => line.Substring(p, l).Trim()).ToArray();
var message = new
{
message_length = int.Parse(fields[0]),
message_id = int.Parse(fields[1]),
message_type = fields[2],
message_sequence = int.Parse(fields[3]),
car_Id = fields[4],
parts =
Enumerable
.Range(0, 3)
.Select(x => x * 2 + 5)
.Select(x => new Part
{
Price = decimal.Parse(fields[x]),
Manufacturer = fields[x + 1]
}).ToArray(),
};
}
public class Part
{
public decimal Price { get; set; }
public string Manufacturer { get; set; }
}
关于我使用的示例数据(我必须修复它,因为它在你的问题中似乎已损坏,即使我删除了 |
并将 -
替换为空格),我得到这个结果:
我在 a 中有一个固定长度的字符串消息,如下所示:
"[=11=][=11=][=11=]j[=11=][=11=][=11=]\vT3A1111 2999BOSH 2100021 399APV 2100022 "
此消息是我将字节 [] 读入 StringBuilder 以构建字符串而创建的。
上面,字符串部分“[=16=][=16=][=16=]j[=16=][=16=][=16=]\v
”应该是LENGTH和ID字段,都是4字节长。但是,我不确定如何提取这 2 个值,但我可以看到 HEX 0j
是 106(1+1+8+9+30+9+9+30+9=106 总长度)。我不确定为什么 "v" 不是上面的“0v”,但我知道它应该是代表消息 ID 的十六进制值。
前 2 个长度为 4 的字段是 HEX,其他都是 ASCII。
这不是 EDI 消息(因此不能使用 EDI 解析器库)并且与具有某种字段标识符的 EDI 消息不同,我只有字节流并且我只知道字段的长度。这些字段是:
4 byte long message length ("[=12=][=12=][=12=]j")
4 byte long message id ("[=12=][=12=][=12=]\v")
1 byte long message type ("T")
1 byte long message sequence ("3")
8 byte long car Id ("A1111 ")
9 byte long part-1 price (" 2999")
30 byte long part-1 manufacturer ("BOSH ")
9 byte long part# ("2100021 ")
9 byte long part-2 price (" 399")
30 byte long part-2 manufacturer ("APV ")
9 byte long part# ("2100022 ")
所以,上面我有 2 个零件由 2 个制造商制造,但在实际示例中,它可能不仅仅是 2 个:
Part 1, 29.99, made by Bosh, part# 2100021
Part 2, 3.99, made by APV, part# 2100022
我想将所有价格和制造商字段从这个平面文件字符串中提取到 Part 所在的列表对象中
class Part
{
public decimal Price {get; set}
public string Manufacturer {get; set;}
public string PartNumber {get; set;}
}
因此,我的列表将包含所有零件及其价格和制造商。
因为我知道每个字段的长度,所以我知道我可以循环遍历这个字符串并获取与零件相关的数据。但是,我想知道是否有更优雅、更简单的方法来做到这一点。
或者更好的是,是否有一个开源库允许我解析这样的东西?
我用这种方法收到这条消息
private TcpClient clientSocket;
private NetworkStream serverStream;
private async System.Threading.Tasks.Task ReadResponseAsync()
{
if (serverStream.CanRead)
{
byte[] readBuffer = new byte[1024];
StringBuilder receivedMessage = new StringBuilder();
int readSoFar = 0;
do
{
readSoFar = await serverStream.ReadAsync(readBuffer, 0, readBuffer.Length);
receivedMessage.AppendFormat("{0}", Encoding.ASCII.GetString(readBuffer, 0, readSoFar));
}
while (serverStream.DataAvailable);
string msg = receivedMessage.ToString();
}
else
{
Log("Error", "Cannot read from NetworkStream");
}
}
@Enigmativity - 我尝试在 LinqPad 中发布你的答案并运行它(从未使用过它,只是下载并安装了它)但我没有看到你在你的帖子中发布的类似 table 的结构回答。你是怎么得到的?
这是我得到的
你说"byte[] into a StringBuilder to build string",所以我认为你有一个字符串。也许尝试使用 SubString(..),类似于:
var length = int.Parse(message.SubString(0,4);
var id = int.Parse(message.SubString(4,4);
等等
编辑:如果有不需要的填充字符,请尝试
message.Replace('-', ' ');
不优雅,但它会工作。
也许试试这样的方法:
void Main()
{
var line = "00580011T3A1111 2999Bosh 399APV 2399MAG ";
var lengths = new[] { 4, 4, 1, 1, 8, 9, 30, 9, 30, 9, 30 };
var starts = lengths.Aggregate(new[] { 0 }.ToList(), (a, x) => { a.Add(a.Last() + x); return a; });
var fields = starts.Zip(lengths, (p, l) => line.Substring(p, l).Trim()).ToArray();
var message = new
{
message_length = int.Parse(fields[0]),
message_id = int.Parse(fields[1]),
message_type = fields[2],
message_sequence = int.Parse(fields[3]),
car_Id = fields[4],
parts =
Enumerable
.Range(0, 3)
.Select(x => x * 2 + 5)
.Select(x => new Part
{
Price = decimal.Parse(fields[x]),
Manufacturer = fields[x + 1]
}).ToArray(),
};
}
public class Part
{
public decimal Price { get; set; }
public string Manufacturer { get; set; }
}
关于我使用的示例数据(我必须修复它,因为它在你的问题中似乎已损坏,即使我删除了 |
并将 -
替换为空格),我得到这个结果: