RegEx带位掩码?
我有一个部分二进制数据流,我想匹配时,在字符串中某个位置的某个字节中设置了某个位。RegEx带位掩码?
这在使用System.Text.RegularExpressions
其被配置成与数量的图案.NET现有系统 - 当特定模式匹配,则匹配触发一个动作。
我接口到一个设备,其中的指标之一是唯一可用的位字段内。
我能看到的唯一的选择是符合整个等价类所有有位设置的字节数。
这是一个梅特勒 - 托利多量表接口。
流是这样的:
STX
SWA
SWB
SWC
WEIGHT (6 bytes ASCII)
TARE (6 bytes ASCII)
0x0D (CR)
(Optional checksum)
凡SWA
,SWB
,SWC
是状态字字节,我很感兴趣的SWB
第3位。
他们总是设置位5:1,在所有这些状态字,所以它是一个空间(0x20
)时,没有位被设置。所以实际上没有其他状态比特通过,SWB
在(
(0x50
-01010000
)和SPACE(0x20
-00100000
)之间的交替变化。实际上,比例也可能在我不在乎的其他状态中发送比特0和4关于。
所以我可以匹配..[\(all other equivalent characters]..{6}.{6}\r\0
如果我理解正确的话,对于SWB
唯一可能的值(二进制)001xx00x
,你只需要使用正则表达式来区分001x000x
(位3 = 0
)从001x100x
(位3 = 1
)。那是对的吗?如果是这样,那么你可以使用这个字符类检测时,位3 = 0
:
[\u0020\u0021\u0030\u0031]
而这一次检测时,位3 = 1
:
如果有更多不同的可能值对于SWB
,那么它可能值得做更聪明的事情,但事实是,我不认为有这种需要。
这是正确的。如果可能设置其他位,我将不得不添加其他等效字节。 – 2012-08-07 17:36:25
实际上,我将不得不重新编译这个东西,使用一些替代的逻辑/配置,这个规模不依赖于简单的正则表达式,并试图找出如何在稍后将其重构为一致的配置。 – 2012-08-07 17:38:47
@CadeRoux:Re:创建一个备用的非正则表达式配置:是的,我认为这是正确的选择。 :-) – ruakh 2012-08-08 12:25:42
当涉及到正则表达式,字符是一个不可分割的组成单位,所以你需要以一个字符内匹配位,创建一个字符类。
有两种方法可以在字符类中包含或排除一组字符 - 通过单独列出它们(如[asdfg]
),或者指定一个范围(如[a-z]
)。
在最糟糕的情况下,您的组将包含128个覆盖单个位的元素。但是,如果您匹配较高位,则可以使用范围将连续字符组合在一起。
例如,匹配位8是
[\u0080-\u00FF]
匹配位7是
[\u0040-\u007F\u00C0-\u00FF]`
匹配位6是
[\u0020-\u003F\u0060-\u007F\u0060-\u007F\u00E0-\u00FF]
等。
您已经从低速输入设备获得了一串短而长的固定长度的记录。使用正则表达式来读取/解析这个看起来像使用锤子来驱动螺丝钉。
为什么不只是将BinaryReader
的数据读入自定义类并将其作为对象进行处理?更容易理解,更易于维护。
事情是这样的:
static void Main(string[] args)
{
using (Stream s = OpenStream())
using (BinaryReader reader = new BinaryReader(s , Encoding.ASCII))
{
foreach (ScaleReading reading in ScaleReading.ReadInstances(reader))
{
if (!reading.IsValid) continue ; // let's just skip invalid data, shall we?
bool isInteresting = (reading.StatusB & 0x08) == 0x08 ;
if (isInteresting)
{
ProcessInterestingReading(reading) ;
}
}
}
return;
}
其中ScaleReading
看起来是这样的:
class ScaleReading
{
private ScaleReading(byte[] data , int checkSum)
{
this.Data = data ;
this.CheckSum = checkSum ;
this.ComputedCheckSum = ComputeCheckSumFromData(data) ;
this.STX = data[0] ;
this.StatusA = data[1] ;
this.StatusB = data[2] ;
this.StatusC = data[3] ;
this.Weight = ToInteger(data, 4, 6) ;
this.Tare = ToInteger(data, 10,6) ;
this.CR = data[16] ;
}
private int ToInteger(byte[] data , int offset , int length)
{
char[] chs = Encoding.ASCII.GetChars(data , offset , length) ;
string s = new String(chs) ;
int value = int.Parse(s) ;
return value ;
}
private int ComputeCheckSumFromData(byte[] data)
{
//TODO: compute checksum from data octets
throw new NotImplementedException();
}
public bool IsValid
{
get
{
bool isValid = ComputedCheckSum == CheckSum
&& STX == '\x0002' // expected STX char is actually STX
&& CR == '\r' // expected CR char is actually CR
;
return isValid ;
}
}
public byte[] Data { get ; private set ; }
public int ComputedCheckSum { get ; private set ; }
public int CheckSum { get ; private set ; }
public byte STX { get ; private set ; } // ?
public byte StatusA { get ; private set ; } // might want to make each of status word an enum
public byte StatusB { get ; private set ; } // might want to make each of status word an enum
public byte StatusC { get ; private set ; } // might want to make each of status word an enum
public int Weight { get ; private set ; }
public int Tare { get ; private set ; }
public byte CR { get ; private set ; }
public static ScaleReading ReadInstance(BinaryReader reader)
{
ScaleReading instance = null;
byte[] data = reader.ReadBytes(17);
if (data.Length > 0)
{
if (data.Length != 17) throw new InvalidDataException() ;
int checkSum = reader.ReadInt32() ;
instance = new ScaleReading(data , checkSum);
}
return instance;
}
public static IEnumerable<ScaleReading> ReadInstances(BinaryReader reader)
{
for (ScaleReading instance = ReadInstance(reader) ; instance != null ; instance = ReadInstance(reader))
{
yield return instance ;
}
}
}
因为当我有其他工作要做时,我不想改变另一个古怪的书面传统程序。所以是的,现在它有一个特殊的模式来完成你写的东西,希望这个源代码是正确的版本,这个版本会很好的测试。 – 2012-08-07 19:37:25
这是对我来说太抽象:)你能也许用一个例子澄清你的问题? – dasblinkenlight 2012-08-07 16:59:11