2007-05-18

.Net/Java 风格格式化字符串

关键字: Dotmars D

基础类库的东西看起来容易做起来难,今天花时间实现了一点点 .Net 风格的字符串格式化函数,贴出来娱乐一下。

注意:目前仅支持占位符索引号而已...

  1. import std.stdio;
  2. import std.string;
  3. import std.conv;
  4. alias void delegate(char c) Sink;
  5. alias void* Argument;
  6. const size_t MaxArguments = 16;
  7. void format(char[] fmt, Sink sink, Argument argPtr, TypeInfo[] argtis)
  8. {
  9. assert(argtis.length <= MaxArguments, "format: Too many arguments");
  10. Argument[MaxArguments] args = void;
  11. //填充参数指针
  12. foreach (size_t i, ti; argtis)
  13. {
  14. args[i] = argPtr;
  15. //来自于 stdarg.d,避免不同CPU建构中堆栈结构差异
  16. argPtr += (ti.tsize + int.sizeof - 1) & ~ (int.sizeof - 1);
  17. }
  18. doFormat(fmt, sink, args, argtis);
  19. }
  20. void format(char[] fmt, Sink sink, ...)
  21. {
  22. format(fmt, sink, _argptr, _arguments);
  23. }
  24. size_t skipSpaces(char[] str)
  25. {
  26. size_t i;
  27. for(i = 0; i < str.length; i++)
  28. {
  29. if(str[i] != ' ')return i;
  30. }
  31. return i;
  32. }
  33. uint extractNumber(char[] str)
  34. {
  35. size_t len = 0;
  36. foreach(char c; str)
  37. {
  38. if(c >= '0' && c <= '9') len++;
  39. else break;
  40. }
  41. if(len == 0)
  42. throw new Exception("Format: syntax error");
  43. return toUint(str[0 .. len]);
  44. }
  45. size_t findRightBrach(char[] str)
  46. {
  47. foreach(size_t i, char c; str)
  48. {
  49. if(c == '}')
  50. return i;
  51. }
  52. //大括号不匹配
  53. throw new Exception("Format: Syntax error");
  54. }
  55. void doFormat(char[] fmt, Sink sink, Argument[] args, TypeInfo[] ti)
  56. {
  57. for(size_t i = 0; i < fmt.length;)
  58. {
  59. //跳过非占位符
  60. for(; i < fmt.length && fmt[i] != '{'; i++)
  61. sink(fmt[i]);
  62. if(i >= fmt.length)break;
  63. // "{{" 转义,输出 '{' 即可
  64. if(i < fmt.length - 1 && fmt[i + 1] == '{')
  65. {
  66. i += 2;
  67. sink('{');
  68. continue;
  69. }
  70. size_t beginBrach = i;
  71. size_t endBrach = i + findRightBrach(fmt[i .. $]);
  72. // parsing the format string
  73. doParse(fmt[beginBrach + 1 .. endBrach], sink, args, ti);
  74. i = endBrach + 1;
  75. }
  76. }
  77. void doParse(char[] fmt, Sink sink, Argument[] args, TypeInfo[] ti)
  78. {
  79. size_t i = 0;
  80. i += skipSpaces(fmt);
  81. //提取索引号
  82. uint index = extractNumber(fmt);
  83. ////TODO: 其他类型支持在此处添加
  84. int *iptr = cast(int*)args[index];
  85. foreach(char c; std.string.toString(*iptr))
  86. sink(c);
  87. }
  88. void print(char[] fmt, ...)
  89. {
  90. void sink(char c)
  91. {
  92. writef(c);
  93. }
  94. format(fmt, &sink, _argptr, _arguments);
  95. }
  96. void main()
  97. {
  98. print("Hello {0} {2} brach{{}}brach {1} Dotmars\n", 111, 2222, 333);
  99. }

评论
DavidL 2007-05-20
呵呵,是我的话抄袭Tango的就算了
发表评论

您还没有登录,请登录后发表评论

oldrev
搜索本博客
我的相册
7e9318d5-c74f-36e0-81a3-beb68acaa2b8-thumb
Screenshot
共 1 张
最近加入圈子
存档
最新评论