2013-07-17 28 views
0

我目前的项目处理大量的传入无线电消息(~5M每天)表示为字符串,必须然后划分成预先确定大小的块,准备存储。最有效的方式分裂许多字符串

例如,消息会在以下格式:

mzIIIICCssss

每个不同炭表示一块,所以本实施例中保持5块(M,Z,IIII,CC,SSSS)。

使用格式的消息的例子是:(。,9,1234,NE,0001)

.91234NE0001

我用substring到目前为止,但都被告知这是不是像正则表达式一样高效。如果是这样的话,我怎样才能使用regex匹配字符位置而不是语义模式?

+3

传入消息的格式不清楚。他们是否总是需要分成完全相同的长度? – RoadieRich

+3

我不认为正则表达式比普通的'Substring'调用会更快。 –

+2

_“已被告知”_--不相信谣言,使用基准。 – CodeCaster

回答

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方法更快,但我以前曾想过错误的方法。它可能会有相同的速度。

+3

即使它是真实的,也只是评论imho。 –

+2

@TimSchmelter它根据我的理解回答这个问题。 –

+0

因此,使用子串时的字符串不可变性不是真正的问题? – Lee

2

忽视的问题,其中解决方案是最有效的,这里是一个正则表达式将匹配(mzIIIICCssss

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

这将一个名为“M”组中捕获一个字符的问题给出的格式中,一个名为“z”的组中的下一个字符,一个名为“IIII”的组中的下一个4个字符,“CC”中的下一个2以及“ssss”中的下一个4。

就性能而言,如果您现在使用的代码速度不够快,并且您已经确定字符串处理是分析它的问题,那么请查找更快的替换。

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 
{ 
    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

+0

是不是这种......矫枉过正? –

+0

他说他想要高效。没有比直接提取字符更有效的了。 – Romoku

+0

@KendallFrey事实证明,'不安全'的代码仍然比安全代码慢。 – Romoku

相关问题