【问题标题】:dart efficient string processing techniques?dart 高效的字符串处理技术?
【发布时间】:2014-02-28 17:44:40
【问题描述】:

name:key:dataLength:data 格式的字符串,这些字符串通常可以链接在一起。例如 "aNum:n:4:9879aBool:b:1:taString:s:2:Hi" 这将映射到类似的对象:

{
  aNum: 9879,
  aBool: true,
  aString: "Hi"
}

我有一种解析这种格式的字符串的方法,但我不确定是否使用substring 是处理字符串的最有效方式,是否有更有效的方式以这种方式处理字符串(反复砍掉前面的部分):

Map<string, dynamic> fromString(String s){
  Map<String, dynamic> _internal = new Map();
  int start = 0;
  while(start < s.length){
    int end;
    List<String> parts = new List<String>(); //0 is name, 1 is key, 2 is data length, 3 is data
    for(var i = 0; i < 4; i++){
      end = i < 3 ? s.indexOf(':') : num.parse(parts[2]);
      parts[i] = s.substring(start, end);
      start = i < 3 ? end + 1 : end;
    }
    var tranType = _tranTypesByKey[parts[1]]; //this is just a map to an object which has a function that can convert the data section of the string into an object
    _internal[parts[0]] = tranType._fromStr(parts[3]);
  }
  return _internal;
}

【问题讨论】:

  • 您能否提供有关此类字符串的预期大小或您希望一次处理多少此类字符串的信息。这取决于很多这样的信息,什么策略是有意义的,或者花时间进行优化是否有意义。
  • 字符串的数据部分在大小和内容方面绝对可以是任何东西,并且这些对象的链接也可能是巨大的,我不希望它们成为我使用它们的个人原因只会使用小型简单对象,但类应支持具有任意数量属性的对象。
  • 那么您也可以考虑使用流进行异步处理并使用Finite State Machine 进行解析,因此您不需要同时在内存中拥有多个副本。您也可以在仍在接收数据时开始处理数据。对于小块可能会慢一些,但对于大数据可能会更快。
  • 为什么不直接使用 json 或 ProtocolBuffers 和现有的解析器呢? (当然,前提是您可以决定将哪种格式用于编码数据)

标签: string dart


【解决方案1】:

我会尝试s.split(':') 并处理结果列表。 如果你做了很多这样的操作,你应该考虑创建基准测试,尝试不同的技术并进行比较。

如果你还需要这条线

 s = i < 3 ? s.substring(idx + 1) : s.substring(idx);

我会避免在每次迭代中创建一个新的子字符串,而是只跟踪next 的位置。

【讨论】:

  • 我没有选择split(':') 的唯一原因是因为我不能保证字符串的数据部分不会包含:,所以我最终会加入那些位再次备份。关于跟踪下一个位置而不是反复覆盖原始字符串的好技巧。
  • 我明白了。你的分隔符是:x:y:,其中x 是一些类型信息,y 是字段标识符。您可以为此尝试正则表达式。我听说 Dart 正则表达式还不是很快,但我会考虑并对其进行基准测试。
【解决方案2】:

您必须确定性能相对于代码的可读性和可维护性的重要性。

也就是说,您不应该反复切断字符串的头部。这肯定是低效的 - 只需创建那些尾字符串,它就会花费与字符串中记录数成二次方的时间。

为了解析每个字段,您可以避免在长度和类型字段上做子字符串。对于长度字段,您可以自己构建数字:

int index = ...;
// index points to first digit of length.
int length = 0;
int charCode = source.codeUnitAt(index++);
while (charCode != CHAR_COLON) {
   length = 10 * length + charCode - 0x30;
   charCode = source.codeUnitAt(index++);
}
// index points to the first character of content.

由于长度通常是小整数(小于 2

类型字段是单个 ASCII 字符,因此您可以使用 codeUnitAt 获取其 ASCII 值而不是创建单个字符串(然后您的内容解释查找将需要打开字符代码而不是字符串)。

对于解析内容,您可以传递源字符串、起始索引和长度,而不是创建子字符串。那么布尔解析器也可以只读取代码单元而不是单例字符串,字符串解析器可以只生成子字符串,而数字解析器可能也必须生成子字符串并调用 double.parse。

如果 Dart 有一个 double.parseSubstring(source, [int from = 0, int to]) 可以将子字符串解析为双精度而不创建子字符串会很方便。

【讨论】:

  • 谢谢,这正是我正在寻找的另类想法
猜你喜欢
  • 2013-08-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-24
  • 1970-01-01
  • 2013-09-13
  • 2021-12-05
  • 1970-01-01
相关资源
最近更新 更多