我有一个部分二进制数据流,我希望在字符串中某个位置的字节中设置某个位时进行匹配。
这是.NET中使用System.Text.RegularExpressions
的现有系统,它配置了许多模式 - 当某些模式匹配时,匹配会触发一个动作。
我正在连接一个设备,其中一个指标仅在位域内可用。
我能看到的唯一选择是匹配具有该位设置的所有字节的整个等价类。
这是Mettler-Toledo比例界面。
流看起来像这样:
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
答案 0 :(得分:1)
如果我理解正确,SWB
的唯一可能值是(二进制)001xx00x
,您只需要使用正则表达式来区分001x000x
(第3位= {{ 1}})来自0
(第3位= 001x100x
)。那是对的吗?如果是这样,那么您可以使用此字符类来检测第3位= 1
:
0
这个用来检测第3位= [\u0020\u0021\u0030\u0031]
:
1
如果[\u0028\u0029\u0038\u0039]
有更多不同的可能值,那么可能值得做一些更聪明的事情,但事实上,我认为没有必要。
答案 1 :(得分:1)
当涉及正则表达式时,字符是不可分割的原子单元,因此您需要创建一个字符类以匹配字符中的位。
有两种方法可以在字符类中包含或排除一组字符 - 通过单独列出,如[asdfg]
中所列,或指定范围,如[a-z]
。
在最坏的情况下,您的组将包含128个元素,覆盖一个位。但是,如果要匹配高阶位,则可以使用范围将连续字符组合在一起。
例如,匹配位8是
[\u0080-\u00FF]
匹配位7是
[\u0040-\u007F\u00C0-\u00FF]`
匹配位6是
[\u0020-\u003F\u0060-\u007F\u0060-\u007F\u00E0-\u00FF]
等等。
答案 2 :(得分:0)
除非我理解你错了 - 你正在寻找在字符串以外的东西上应用正则表达式(在上面的例子中,是一个位域)。
查看链接到在流上应用正则表达式匹配的方法的this线程。然后,您可以正确地将数据提供给匹配器,
答案 3 :(得分:0)
你有一个来自慢速输入设备的短,固定长度记录流。使用正则表达式来读取/解析这似乎就像用锤子来驱动螺丝一样。
为什么不将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 ;
}
}
}