4

我有一个部分二进制数据流,我想在字符串中某个位置的字节中设置某个位时进行匹配。

这是 .NET 中的现有系统,使用System.Text.RegularExpressions它配置了许多模式 - 当某些模式匹配时,匹配会触发一个动作。

我正在连接一个设备,其中一个指标仅在位域中可用。

我能看到的唯一选择是匹配设置了该位的所有字节的整个等价类。

这是一个梅特勒-托利多秤界面。

流看起来像这样:

STX
SWA
SWB
SWC
WEIGHT (6 bytes ASCII)
TARE (6 bytes ASCII)
0x0D (CR)
(Optional checksum)

其中SWA, SWB,SWC是状态字字节,我对 . 的第 3 位感兴趣SWB

它们总是将所有这些状态字中的第 5 位设置为 1,以便0x20在未设置任何位时它是一个空格 ( )。所以在实践中,没有其他状态位通过,在( - ) 和 SPACE ( - )SWB之间交替。实际上,秤也可能在我不关心的其他状态下发送位 0 和 4。(0x50010100000x2000100000

所以我可以匹配..[\(all other equivalent characters]..{6}.{6}\r\0

4

4 回答 4

2

对于正则表达式,字符是不可分割的原子单元,因此您需要创建一个字符类来匹配字符中的位。

有两种方法可以在字符类中包含或排除一组字符 - 通过单独列出它们,如在 中[asdfg],或通过指定范围,如在 中[a-z]

在最坏的情况下,您的组将包含覆盖单个位的 128 个元素。但是,如果您要匹配高阶位,则可以使用范围将连续字符组合在一起。

例如,匹配位 8 是

[\u0080-\u00FF]

匹配位 7 是

[\u0040-\u007F\u00C0-\u00FF]`

匹配位 6 是

[\u0020-\u003F\u0060-\u007F\u0060-\u007F\u00E0-\u00FF]

等等。

于 2012-08-07T18:02:37.423 回答
1

如果我理解正确,唯一可能的值SWB是 (in binary) 001xx00x,您只需要使用正则表达式来区分001x000x(bit 3 = 0) 和001x100x(bit 3 = 1)。那是对的吗?如果是这样,那么您可以使用此字符类来检测位 3 = 的0时间:

[\u0020\u0021\u0030\u0031]

而这个用于检测位 3 = 的1时间:

[\u0028\u0029\u0038\u0039]

如果 有更多不同的可能值SWB,那么可能值得做一些更聪明的事情,但事实上,我认为没有必要。

于 2012-08-07T17:26:42.400 回答
0

除非我理解错了-您希望对字符串以外的事物应用正则表达式(在上面的示例中,位域)。

查看链接到方法以在流上应用正则表达式匹配的这个线程。然后,您可以正确地将数据提供给匹配器,即

于 2012-08-07T17:19:05.233 回答
0

你有一个来自慢速输入设备的短的、固定长度的记录流。使用正则表达式来读取/解析这似乎是使用锤子来驱动螺丝。

为什么不直接将带有 a 的数据读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-07T19:19:34.097 回答