0

我当前的项目处理大量传入的无线电消息(每天约 5M)表示为字符串,然后必须将其划分为预定大小的块,以备存储。

例如,一条消息将采用以下格式:

mzIIIICCssss

每个不同的 char 代表一个块,因此这个示例包含 5 个块(m、z、IIII、CC、ssss)。

使用该格式的消息示例可能是:

.91234NE0001(., 9, 1234, 东北, 0001)

到目前为止我已经使用过substring,但被告知这不如说正则表达式那么有效。如果是这种情况,我如何使用regex匹配字符位置而不是语义模式?

4

3 回答 3

5

Substring比正则表达式快得多。由于您要做的只是将字符串分成固定大小的块,因此只需使用Substring.


cHao的评论给了我另一个想法。您可以使用string(char[], int, int)构造函数,有点像这样:

string message = ".91234NE0001";
char[] messageArr = message.ToCharArray();
string chunk1 = new string(messageArr, 0, 1);
string chunk2 = new string(messageArr, 1, 1);
string chunk3 = new string(messageArr, 2, 4);
string chunk4 = new string(messageArr, 6, 2);
string chunk5 = new string(messageArr, 8, 4);

您可能可以给变量更好的名称:)

这是做Substring正在做的事情的手动方式。我认为它会比Substring方法更快,但我之前在考虑错误的方法。它可能会是大约相同的速度。

于 2013-07-17T14:13:41.393 回答
3

我认为在不使用本机代码的情况下能够实现的最有效的方法是使用不安全的代码。

private static IEnumerable<string> ExtractChunksUnsafe(string format, string data)
{
    if(format.Length != data.Length)
        throw new ArgumentException("Format length must match Data length");

    if(data.Length == 0)
        throw new ArgumentException("Invalid Data length");

    char prevFormat = '\0';
    char currentFormat = format[0];

    var chunks = new List<string>();
    var builder = new StringBuilder();

    unsafe
    {
        fixed(char * indexer = data)
        {
            var index = -1;

            while(data.Length > ++index)
            {
                prevFormat = currentFormat;
                currentFormat = format[index];

                if(currentFormat != prevFormat)
                {
                    chunks.Add(builder.ToString());
                    builder.Clear();
                }

                builder.Append((*(indexer + index)));
            }

            chunks.Add(builder.ToString());
            builder.Clear();
        }
    }

    return chunks;
}

比较:

private static IEnumerable<string> ExtractChunks(string format, string data)
{
    if(format.Length != data.Length)
        throw new ArgumentException("Format length must match Data length");

    if(data.Length == 0)
        throw new ArgumentException("Invalid Data length");

    char prevFormat = '\0';
    char currentFormat = format[0];

    var prevIndex = 0;
    var index = 1;

    var message = data.ToCharArray();
    var chunks = new List<string>();

    while(data.Length > index)
    {
        prevFormat = currentFormat;
        currentFormat = format[index];

        if(currentFormat != prevFormat)
        {
            chunks.Add(new string(message, prevIndex, index - prevIndex));
            prevIndex = index;
        }

        index++;
    }

    chunks.Add(new string(message, prevIndex, index - prevIndex));

    return chunks;
}

样本:

string format = "mzIIIICCssss";
string data = ".a9876NE9001";

var chunks = ExtractChunks(format, data);

foreach(var message in chunks)
{
    Console.WriteLine(message);
}

基准:

string format = "mzIIIICCssss";
string data = ".a9876NE9001";

// Warmup CLR
ExtractChunksUnsafe(format, data);
ExtractChunks(format, data);

TimeSpan unsafeCode;
TimeSpan safeCode;

var timer = Stopwatch.StartNew();

for(int i = 0; i < 10000000; i++)
{
    ExtractChunksUnsafe(format, data);
}

unsafeCode = timer.Elapsed;
timer.Restart();

for(int i = 0; i < 10000000; i++)
{
    ExtractChunks(format, data);
}

safeCode = timer.Elapsed;
timer.Stop();


Console.WriteLine("Unsafe time {0}", unsafeCode);
Console.WriteLine("Safe time {0}", safeCode);

结果:

Unsafe time 00:00:04.8551136
Safe time 00:00:03.1786573

甚至修改 Unsafe 主体:

unsafe
{
    fixed(char * indexer = data)
    {
        var prevIndex = 0;
        var index = 1;

        while(data.Length > index)
        {
            prevFormat = currentFormat;
            currentFormat = format[index];

            if(currentFormat != prevFormat)
            {
                chunks.Add(new string(indexer, prevIndex, index - prevIndex));
                prevIndex = index;
            }

            index++;
        }

        chunks.Add(new string(indexer, prevIndex, index - prevIndex));
    }
}

仍然会导致时间变慢Unsafe time 00:00:03.4565302

于 2013-07-17T14:37:16.223 回答
2

忽略哪种解决方案最有效的问题,这里有一个正则表达式,它将匹配问题 ( mzIIIICCssss)中给出的格式

(?<m>.)(?<z>.)(?<IIII>.{4})(?<CC>.{2})(?<ssss>.{4})

这将捕获名为“m”的组中的一个字符,名为“z”的组中的下一个字符,名为“IIII”的组中的接下来的 4 个字符,“CC”中的下一个 2,以及“ ssss”。

就性能而言,如果您现在拥有的代码不够快,并且您已经通过分析确定字符串处理是问题所在,那么请寻找更快的替代品。

于 2013-07-17T14:23:46.660 回答