最近在考虑写一个可以跨平台的通用字符串类,首先需要搞定的就是编码转换问题。

vs默认保存代码文件,使用的是本地code(中文即GBK,日文即Shift-JIS),也可以使用带BOM的UTF-8。
gcc则是UTF-8,有无BOM均可(源代码的字符集可以由参数-finput-charset指定)。
那么源代码可以采用带BOM的UTF-8来保存。而windows下的unicode是UTF-16编码;Linux则使用UTF-8或UTF-32。因此不论在哪种系统里,程序在处理字符串时都需要考虑UTF编码之间的相互转换。

下面直接贴出算法代码。算法上我借鉴了秦建辉(http://blog.csdn.net/jhqin)的UnicodeConverter,只是在外面增加了一些泛型处理,让使用相对简单。

核心算法(来自UnicodeConverter):

  1. namespace transform
  2. {
  3. /*
  4. UTF-32 to UTF-8
  5. */
  6. inline static size_t utf(uint32 src, uint8* des)
  7. {
  8. if (src == 0) return 0;
  9. static const byte PREFIX[] = { 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
  10. static const uint32 CODE_UP[] =
  11. {
  12. 0x80,           // U+00000000 - U+0000007F
  13. 0x800,          // U+00000080 - U+000007FF
  14. 0x10000,        // U+00000800 - U+0000FFFF
  15. 0x200000,       // U+00010000 - U+001FFFFF
  16. 0x4000000,      // U+00200000 - U+03FFFFFF
  17. 0x80000000      // U+04000000 - U+7FFFFFFF
  18. };
  19. size_t i, len = sizeof(CODE_UP) / sizeof(uint32);
  20. for(i = 0; i < len; ++i)
  21. if (src < CODE_UP[i]) break;
  22. if (i == len) return 0; // the src is invalid
  23. len = i + 1;
  24. if (des)
  25. {
  26. for(; i > 0; --i)
  27. {
  28. des[i] = static_cast<uint8>((src & 0x3F) | 0x80);
  29. src >>= 6;
  30. }
  31. des[0] = static_cast<uint8>(src | PREFIX[len - 1]);
  32. }
  33. return len;
  34. }
  35. /*
  36. UTF-8 to UTF-32
  37. */
  38. inline static size_t utf(const uint8* src, uint32& des)
  39. {
  40. if (!src || (*src) == 0) return 0;
  41. uint8 b = *(src++);
  42. if (b < 0x80)
  43. {
  44. des = b;
  45. return 1;
  46. }
  47. if (b < 0xC0 || b > 0xFD) return 0; // the src is invalid
  48. size_t len;
  49. if (b < 0xE0)
  50. {
  51. des = b & 0x1F;
  52. len = 2;
  53. }
  54. else
  55. if (b < 0xF0)
  56. {
  57. des = b & 0x0F;
  58. len = 3;
  59. }
  60. else
  61. if (b < 0xF8)
  62. {
  63. des = b & 0x07;
  64. len = 4;
  65. }
  66. else
  67. if (b < 0xFC)
  68. {
  69. des = b & 0x03;
  70. len = 5;
  71. }
  72. else
  73. {
  74. des = b & 0x01;
  75. len = 6;
  76. }
  77. size_t i = 1;
  78. for (; i < len; ++i)
  79. {
  80. b = *(src++);
  81. if (b < 0x80 || b > 0xBF) return 0; // the src is invalid
  82. des = (des << 6) + (b & 0x3F);
  83. }
  84. return len;
  85. }
  86. /*
  87. UTF-32 to UTF-16
  88. */
  89. inline static size_t utf(uint32 src, uint16* des)
  90. {
  91. if (src == 0) return 0;
  92. if (src <= 0xFFFF)
  93. {
  94. if (des) (*des) = static_cast<uint16>(src);
  95. return 1;
  96. }
  97. else
  98. if (src <= 0xEFFFF)
  99. {
  100. if (des)
  101. {
  102. des[0] = static_cast<uint16>(0xD800 + (src >> 10) - 0x40);  // high
  103. des[1] = static_cast<uint16>(0xDC00 + (src & 0x03FF));      // low
  104. }
  105. return 2;
  106. }
  107. return 0;
  108. }
  109. /*
  110. UTF-16 to UTF-32
  111. */
  112. inline static size_t utf(const uint16* src, uint32& des)
  113. {
  114. if (!src || (*src) == 0) return 0;
  115. uint16 w1 = src[0];
  116. if (w1 >= 0xD800 && w1 <= 0xDFFF)
  117. {
  118. if (w1 < 0xDC00)
  119. {
  120. uint16 w2 = src[1];
  121. if (w2 >= 0xDC00 && w2 <= 0xDFFF)
  122. {
  123. des = (w2 & 0x03FF) + (((w1 & 0x03FF) + 0x40) << 10);
  124. return 2;
  125. }
  126. }
  127. return 0; // the src is invalid
  128. }
  129. else
  130. {
  131. des = w1;
  132. return 1;
  133. }
  134. }
  135. }

上面这些算法都是针对单个字符的,并且是UTF-32和UTF-16/8之间的互转。
通过上面的算法,可以得到UTF-16和UTF-8之间的单字符转换算法:

  1. namespace transform
  2. {
  3. /*
  4. UTF-16 to UTF-8
  5. */
  6. inline static size_t utf(uint16 src, uint8* des)
  7. {
  8. // make utf-16 to utf-32
  9. uint32 tmp;
  10. if (utf(&src, tmp) != 1) return 0;
  11. // make utf-32 to utf-8
  12. return utf(tmp, des);
  13. }
  14. /*
  15. UTF-8 to UTF-16
  16. */
  17. inline static size_t utf(const uint8* src, uint16& des)
  18. {
  19. // make utf-8 to utf-32
  20. uint32 tmp;
  21. size_t len = utf(src, tmp);
  22. if (len == 0) return 0;
  23. // make utf-32 to utf-16
  24. if (utf(tmp, &des) != 1) return 0;
  25. return len;
  26. }
  27. }

同样,通过上面的单字符转换算法,可以得到整个字符串的转换算法:

  1. namespace transform
  2. {
  3. /*
  4. UTF-X: string to string
  5. */
  6. template <typename T>
  7. size_t utf(const uint32* src, T* des)   // UTF-32 to UTF-X(8/16)
  8. {
  9. if (!src || (*src) == 0) return 0;
  10. size_t num = 0;
  11. for(; *src; ++src)
  12. {
  13. size_t len = utf(*src, des);
  14. if (len == 0) break;
  15. if (des) des += len;
  16. num += len;
  17. }
  18. if (des) (*des) = 0;
  19. return num;
  20. }
  21. template <typename T>
  22. size_t utf(const T* src, uint32* des)   // UTF-X(8/16) to UTF-32
  23. {
  24. if (!src || (*src) == 0) return 0;
  25. size_t num = 0;
  26. while(*src)
  27. {
  28. uint32 tmp;
  29. size_t len = utf(src, tmp);
  30. if (len == 0) break;
  31. if (des)
  32. {
  33. (*des) = tmp;
  34. ++des;
  35. }
  36. src += len;
  37. num += 1;
  38. }
  39. if (des) (*des) = 0;
  40. return num;
  41. }
  42. template <typename T, typename U>
  43. size_t utf(const T* src, U* des)    // UTF-X(8/16) to UTF-Y(16/8)
  44. {
  45. if (!src || (*src) == 0) return 0;
  46. size_t num = 0;
  47. while(*src)
  48. {
  49. // make utf-x to ucs4
  50. uint32 tmp;
  51. size_t len = utf(src, tmp);
  52. if (len == 0) break;
  53. src += len;
  54. // make ucs4 to utf-y
  55. len = utf(tmp, des);
  56. if (len == 0) break;
  57. if (des) des += len;
  58. num += len;
  59. }
  60. if (des) (*des) = 0;
  61. return num;
  62. }
  63. }

有了这些之后,我们已经可以完整的做UTF-8/16/32之间的相互转换了,但是这些函数的使用仍然不是很方便。
比如我现在想把一个UTF-8字符串转换成一个wchar_t*字符串,我得这样写:

  1. const uint8* c = (uint8*)"こんにちわ、世界";
  2. size_t n = (sizeof(wchar_t) == 2) ?
  3. transform::utf(c, (uint16*)0) :
  4. transform::utf(c, (uint32*)0);
  5. wchar_t* s = new wchar_t[n];
  6. if (sizeof(wchar_t) == 2)
  7. transform::utf(c, (uint16*)s);
  8. else
  9. transform::utf(c, (uint32*)s);

这显然是一件很抽搐的事情,因为wchar_t在不同的操作系统(windows/linux)里有不同的sizeof长度。
上面的类型强制转换只是为了去适配合适的函数重载,当然我们也可以通过函数名来区分这些函数:比如分别叫utf8_to_utf32之类的。但是这改变不了写if-else来适配长度的问题。

显然这里可以通过泛型来让算法更好用。
首先,需要被抽离出来的就是参数的类型大小和类型本身的依赖关系:

  1. template <size_t X> struct utf_type;
  2. template <>         struct utf_type<1> { typedef uint8  type_t; };
  3. template <>         struct utf_type<2> { typedef uint16 type_t; };
  4. template <>         struct utf_type<4> { typedef uint32 type_t; };

然后,实现一个简单的check算法,这样后面就可以利用SFINAE的技巧筛选出合适的算法函数:

  1. template <size_t X, typename T>
  2. struct check
  3. {
  4. static const bool value =
  5. ((sizeof(T) == sizeof(typename utf_type<X>::type_t)) && !is_pointer<T>::value);
  6. };

下面我们需要一个detail,即泛型适配的细节。从上面的算法函数参数中,我们可以很容易的观察出一些规律:
只要是由大向小转换(比如32->16,或16->8)的,其对外接口可以抽象成这两种形式:

  1. type_t utf(T src, U* des)
  2. type_t utf(const T* src, U* des)

而由小向大的转换,则是下面这两种形式:

  1. type_t utf(const T* src, U& des)
  2. type_t utf(const T* src, U* des)

再加上第二个指针参数是可以给一个默认值(空指针)的,因此适配的泛型类就可以写成这样:

  1. template <size_t X, size_t Y, bool = (X > Y), bool = (X != Y)>
  2. struct detail;
  3. /*
  4. UTF-X(32/16) to UTF-Y(16/8)
  5. */
  6. template <size_t X, size_t Y>
  7. struct detail<X, Y, true, true>
  8. {
  9. typedef typename utf_type<X>::type_t src_t;
  10. typedef typename utf_type<Y>::type_t des_t;
  11. template <typename T, typename U>
  12. static typename enable_if<check<X, T>::value && check<Y, U>::value,
  13. size_t>::type_t utf(T src, U* des)
  14. {
  15. return transform::utf((src_t)(src), (des_t*)(des));
  16. }
  17. template <typename T>
  18. static typename enable_if<check<X, T>::value,
  19. size_t>::type_t utf(T src)
  20. {
  21. return transform::utf((src_t)(src), (des_t*)(0));
  22. }
  23. template <typename T, typename U>
  24. static typename enable_if<check<X, T>::value && check<Y, U>::value,
  25. size_t>::type_t utf(const T* src, U* des)
  26. {
  27. return transform::utf((const src_t*)(src), (des_t*)(des));
  28. }
  29. template <typename T>
  30. static typename enable_if<check<X, T>::value,
  31. size_t>::type_t utf(const T* src)
  32. {
  33. return transform::utf((src_t)(src), (des_t*)(0));
  34. }
  35. };
  36. /*
  37. UTF-X(16/8) to UTF-Y(32/16)
  38. */
  39. template <size_t X, size_t Y>
  40. struct detail<X, Y, false, true>
  41. {
  42. typedef typename utf_type<X>::type_t src_t;
  43. typedef typename utf_type<Y>::type_t des_t;
  44. template <typename T, typename U>
  45. static typename enable_if<check<X, T>::value && check<Y, U>::value,
  46. size_t>::type_t utf(const T* src, U& des)
  47. {
  48. des_t tmp; // for disable the warning strict-aliasing from gcc 4.4
  49. size_t ret = transform::utf((const src_t*)(src), tmp);
  50. des = tmp;
  51. return ret;
  52. }
  53. template <typename T, typename U>
  54. static typename enable_if<check<X, T>::value && check<Y, U>::value,
  55. size_t>::type_t utf(const T* src, U* des)
  56. {
  57. return transform::utf((const src_t*)(src), (des_t*)(des));
  58. }
  59. template <typename T>
  60. static typename enable_if<check<X, T>::value,
  61. size_t>::type_t utf(const T* src)
  62. {
  63. return transform::utf((const src_t*)(src), (des_t*)(0));
  64. }
  65. };

最后的外敷类收尾就可以相当的简单:

  1. template <typename T, typename U>
  2. struct converter
  3. : detail<sizeof(T), sizeof(U)>
  4. {};

通过上面的detail,我们也可以很轻松的写出一个通过指定8、16这些数字,来控制选择哪些转换算法的外敷模板。
有了converter,同类型的需求(指UTF-8转wchar_t)就可以变得轻松愉快很多:

  1. const char* c = "こんにちわ、世界";
  2. wstring s;
  3. size_t n; wchar_t w;
  4. while (!!(n = converter<char, wchar_t>::utf(c, w))) // 这里的!!是为了屏蔽gcc的警告
  5. {
  6. s.push_back(w);
  7. c += n;
  8. }
  9. FILE* fp = fopen("test_converter.txt", "wb");
  10. fwrite(s.c_str(), sizeof(wchar_t), s.length(), fp);
  11. fclose(fp);

上面这一小段代码是将一段UTF-8的文字逐字符转换为wchar_t,并一个个push_back到wstring里,最后把转换完毕的字符串输出到test_converter.txt里。


其实上面的泛型还是显得累赘了。为什么不直接在transform::utf上使用泛型参数呢?
一开始只想到上面那个方法,自然是由于惯性的想要手动指定如何转换编码的缘故,比如最开始的想法,是想做成类似这样的模板:utf<8, 32>(s1, s2),指定两个数字,来决定输入和输出的格式。

后来发现,直接指定字符串/字符的类型或许更加直接些。
现在回头再看看,其实转换所需要的字长(8、16、32)已经在参数的类型中指定了:8bits的char或byte类型肯定不会是用来存放UTF-32的嘛。。
所以只需要把上面核心算法的参数泛型化就可以了。这时代码就会写成下面这个样子:

  1. namespace transform
  2. {
  3. namespace private_
  4. {
  5. template <size_t X> struct utf_type;
  6. template <>         struct utf_type<1> { typedef uint8  type_t; };
  7. template <>         struct utf_type<2> { typedef uint16 type_t; };
  8. template <>         struct utf_type<4> { typedef uint32 type_t; };
  9. template <typename T, size_t X>
  10. struct check
  11. {
  12. static const bool value =
  13. ((sizeof(T) == sizeof(typename utf_type<X>::type_t)) && !is_pointer<T>::value);
  14. }
  15. }
  16. using namespace transform::private_;
  17. /*
  18. UTF-32 to UTF-8
  19. */
  20. template <typename T, typename U>
  21. typename enable_if<check<T, 4>::value && check<U, 1>::value,
  22. size_t>::type_t utf(T src, U* des)
  23. {
  24. if (src == 0) return 0;
  25. static const byte PREFIX[] = { 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
  26. static const uint32 CODE_UP[] =
  27. {
  28. 0x80,           // U+00000000 - U+0000007F
  29. 0x800,          // U+00000080 - U+000007FF
  30. 0x10000,        // U+00000800 - U+0000FFFF
  31. 0x200000,       // U+00010000 - U+001FFFFF
  32. 0x4000000,      // U+00200000 - U+03FFFFFF
  33. 0x80000000      // U+04000000 - U+7FFFFFFF
  34. };
  35. size_t i, len = sizeof(CODE_UP) / sizeof(uint32);
  36. for(i = 0; i < len; ++i)
  37. if (src < CODE_UP[i]) break;
  38. if (i == len) return 0; // the src is invalid
  39. len = i + 1;
  40. if (des)
  41. {
  42. for(; i > 0; --i)
  43. {
  44. des[i] = static_cast<U>((src & 0x3F) | 0x80);
  45. src >>= 6;
  46. }
  47. des[0] = static_cast<U>(src | PREFIX[len - 1]);
  48. }
  49. return len;
  50. }
  51. /*
  52. UTF-8 to UTF-32
  53. */
  54. template <typename T, typename U>
  55. typename enable_if<check<T, 1>::value && check<U, 4>::value,
  56. size_t>::type_t utf(const T* src, U& des)
  57. {
  58. if (!src || (*src) == 0) return 0;
  59. uint8 b = *(src++);
  60. if (b < 0x80)
  61. {
  62. des = b;
  63. return 1;
  64. }
  65. if (b < 0xC0 || b > 0xFD) return 0; // the src is invalid
  66. size_t len;
  67. if (b < 0xE0)
  68. {
  69. des = b & 0x1F;
  70. len = 2;
  71. }
  72. else
  73. if (b < 0xF0)
  74. {
  75. des = b & 0x0F;
  76. len = 3;
  77. }
  78. else
  79. if (b < 0xF8)
  80. {
  81. des = b & 0x07;
  82. len = 4;
  83. }
  84. else
  85. if (b < 0xFC)
  86. {
  87. des = b & 0x03;
  88. len = 5;
  89. }
  90. else
  91. {
  92. des = b & 0x01;
  93. len = 6;
  94. }
  95. size_t i = 1;
  96. for (; i < len; ++i)
  97. {
  98. b = *(src++);
  99. if (b < 0x80 || b > 0xBF) return 0; // the src is invalid
  100. des = (des << 6) + (b & 0x3F);
  101. }
  102. return len;
  103. }
  104. /*
  105. UTF-32 to UTF-16
  106. */
  107. template <typename T, typename U>
  108. typename enable_if<check<T, 4>::value && check<U, 2>::value,
  109. size_t>::type_t utf(T src, U* des)
  110. {
  111. if (src == 0) return 0;
  112. if (src <= 0xFFFF)
  113. {
  114. if (des) (*des) = static_cast<U>(src);
  115. return 1;
  116. }
  117. else
  118. if (src <= 0xEFFFF)
  119. {
  120. if (des)
  121. {
  122. des[0] = static_cast<U>(0xD800 + (src >> 10) - 0x40);  // high
  123. des[1] = static_cast<U>(0xDC00 + (src & 0x03FF));      // low
  124. }
  125. return 2;
  126. }
  127. return 0;
  128. }
  129. /*
  130. UTF-16 to UTF-32
  131. */
  132. template <typename T, typename U>
  133. typename enable_if<check<T, 2>::value && check<U, 4>::value,
  134. size_t>::type_t utf(const T* src, U& des)
  135. {
  136. if (!src || (*src) == 0) return 0;
  137. uint16 w1 = src[0];
  138. if (w1 >= 0xD800 && w1 <= 0xDFFF)
  139. {
  140. if (w1 < 0xDC00)
  141. {
  142. uint16 w2 = src[1];
  143. if (w2 >= 0xDC00 && w2 <= 0xDFFF)
  144. {
  145. des = (w2 & 0x03FF) + (((w1 & 0x03FF) + 0x40) << 10);
  146. return 2;
  147. }
  148. }
  149. return 0; // the src is invalid
  150. }
  151. else
  152. {
  153. des = w1;
  154. return 1;
  155. }
  156. }
  157. /*
  158. UTF-16 to UTF-8
  159. */
  160. template <typename T, typename U>
  161. typename enable_if<check<T, 2>::value && check<U, 1>::value,
  162. size_t>::type_t utf(T src, U* des)
  163. {
  164. // make utf-16 to utf-32
  165. uint32 tmp;
  166. if (utf(&src, tmp) != 1) return 0;
  167. // make utf-32 to utf-8
  168. return utf(tmp, des);
  169. }
  170. /*
  171. UTF-8 to UTF-16
  172. */
  173. template <typename T, typename U>
  174. typename enable_if<check<T, 1>::value && check<U, 2>::value,
  175. size_t>::type_t utf(const T* src, U& des)
  176. {
  177. // make utf-8 to utf-32
  178. uint32 tmp;
  179. size_t len = utf(src, tmp);
  180. if (len == 0) return 0;
  181. // make utf-32 to utf-16
  182. if (utf(tmp, &des) != 1) return 0;
  183. return len;
  184. }
  185. /*
  186. UTF-X: string to string
  187. */
  188. template <typename T, typename U>
  189. typename enable_if<check<T, 4>::value && (check<U, 1>::value || check<U, 2>::value),
  190. size_t>::type_t utf(const T* src, U* des)   // UTF-32 to UTF-X(8/16)
  191. {
  192. if (!src || (*src) == 0) return 0;
  193. size_t num = 0;
  194. for(; *src; ++src)
  195. {
  196. size_t len = utf(*src, des);
  197. if (len == 0) break;
  198. if (des) des += len;
  199. num += len;
  200. }
  201. if (des) (*des) = 0;
  202. return num;
  203. }
  204. template <typename T, typename U>
  205. typename enable_if<(check<T, 1>::value || check<T, 2>::value) && check<U, 4>::value,
  206. size_t>::type_t utf(const T* src, U* des)   // UTF-X(8/16) to UTF-32
  207. {
  208. if (!src || (*src) == 0) return 0;
  209. size_t num = 0;
  210. while(*src)
  211. {
  212. uint32 tmp;
  213. size_t len = utf(src, tmp);
  214. if (len == 0) break;
  215. if (des)
  216. {
  217. (*des) = tmp;
  218. ++des;
  219. }
  220. src += len;
  221. num += 1;
  222. }
  223. if (des) (*des) = 0;
  224. return num;
  225. }
  226. template <typename T, typename U>
  227. typename enable_if<(check<T, 1>::value && check<U, 2>::value) ||
  228. (check<T, 2>::value && check<U, 1>::value),
  229. size_t>::type_t utf(const T* src, U* des)    // UTF-X(8/16) to UTF-Y(16/8)
  230. {
  231. if (!src || (*src) == 0) return 0;
  232. size_t num = 0;
  233. while(*src)
  234. {
  235. // make utf-x to utf-32
  236. uint32 tmp;
  237. size_t len = utf(src, tmp);
  238. if (len == 0) break;
  239. src += len;
  240. // make utf-32 to utf-y
  241. len = utf(tmp, des);
  242. if (len == 0) break;
  243. if (des) des += len;
  244. num += len;
  245. }
  246. if (des) (*des) = 0;
  247. return num;
  248. }
  249. }

这样用起来就更加简单了:

  1. const char* c = "你好世界";
  2. size_t n = nx::transform::utf(c, (wchar_t*)0);

完整代码请参考:
https://code.google.com/p/nixy/source/browse/trunk/nixycore/string/transform.h

更多内容请访问:http://darkc.at

http://blog.csdn.net/markl22222/article/details/19770505

UTF-8、UTF-16、UTF-32编码的相互转换(不使用现成的函数)的更多相关文章

  1. UTF-8、UTF-16、UTF-32编码的相互转换

    最近在考虑写一个可以跨平台的通用字符串类,首先需要搞定的就是编码转换问题. vs默认保存代码文件,使用的是本地code(中文即GBK,日文即Shift-JIS),也可以使用带BOM的UTF-8.gcc ...

  2. Ansi、GB2312、GBK、Unicode(utf8、16、32)

    关于ansi,一般默认为本地编码方式,中文应该是gb编码 他们之间的关系在这边文章里描写的很清楚:http://blog.csdn.net/ldanduo/article/details/820353 ...

  3. c# 字符串(含有汉字)转化为16进制编码(转)

    public static string Str2Hex(string s) { string result = string.Empty; byte[] arrByte = System.Text. ...

  4. [原创]obj-c编程16:键值编码(KVC)

    原文链接:obj-c编程16:键值编码(KVC) 我们可以借助obj-c中的键值编码(以后简称KVC,Key-Value Coding)来存取类的属性,通过指定所要访问的属性名字符串标示符,可以使用存 ...

  5. 外设位宽为8、16、32时,CPU与外设之间地址线的连接方法

    有不少人问到:flash连接CPU时,根据不同的数据宽度,比如16位的NOR FLASH (A0-A19),处理器的地址线要(A1-A20)左移偏1位.为什么要偏1位? (全文有点晦涩,建议收藏本文对 ...

  6. .NET Core RSA 签名和验签(密钥为 16 进制编码)

    使用 OpenSSL 生成公私钥对,命令: $ openssl genrsa -out rsa_1024_priv.pem $ openssl pkcs8 -topk8 -inform PEM -in ...

  7. MD5、SHA1加密java 16位32位

    MD5.SHA1加密java 16位32位 import java.math.BigInteger; import java.security.MessageDigest; public class ...

  8. java byte数组与16进制间的相互转换

      java byte数组与16进制间的相互转换 CreationTime--2018年6月11日15点34分 Author:Marydon 1.准备工作 import java.util.Array ...

  9. 【Canvas】绘制几何级数Geometric series曲线 y=1+1/2+1/4+1/8+1/16+1/32+1/64+....

    相关资料:https://baike.baidu.com/item/%E5%87%A0%E4%BD%95%E7%BA%A7%E6%95%B0/112584?fr=aladdin 图线: 代码: < ...

随机推荐

  1. 阿里云数据库自研产品亮相国际顶级会议ICDE 推动云原生数据库成为行业标准

    4月9日,澳门当地时间下午4:00-5:30,阿里云在ICDE 2019举办了主题为“云时代的数据库”的专场分享研讨会. 本次专场研讨会由阿里巴巴集团副总裁.高级研究员,阿里云智能数据库产品事业部负责 ...

  2. 1<<33这种写法是错的!!!

    1<<33不能这么写,1默认int类型,应该改为(long long)1<<33

  3. lavarel box 地址

    https://atlas.hashicorp.com/laravel/boxes/homestead download URL https://atlas.hashicorp.com/laravel ...

  4. @loj - 2091@ 「ZJOI2016」小星星

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 小 Y 是一个心灵手巧的女孩子,她喜欢手工制作一些小饰品.她有 ...

  5. Mysql 查询一天中每半小时记录的数量

    SELECT HOUR(e.time)as Hour,FLOOR(MINUTE(e.time)/30) as M, COUNT(*) as Count FROM error_log e WHERE e ...

  6. JAVA内存溢出解析(转)

    JAVA内存溢出解析(转) 核心提示:原因有很多种,比如: 1.数据量过于庞大:死循环 :静态变量和静态方法过多:递归:无法确定是否被引用的对象: 2.虚拟机不回收内存(内存泄漏): 说白了就是程序运 ...

  7. CDN WAF功能开放公测 提升网络应用安全性能

    阿里云CDN WAF功能,是指CDN融合了云盾Web应用防火墙(Web Application Firewall,简称 WAF)能力,在CDN节点上提供安全防护的功能,该功能目前已经开放公测. WAF ...

  8. mysql数据库之单表查询

    单标查询 单表查询语句 关键字执行的优先级 简单查询 where约束 group by 聚合函数 HAVING过滤 order by 查询排序 LIMIT限制查询的记录数 使用正则表达式查询 单表查询 ...

  9. Oracle数据字典全解

    一.概念: 1.数据字典(data dictionary)是 Oracle 数据库的一个重要组成部分,这是一组用于记录数据库信息的只读(read-only)表. 数据字典里存有用户信息.用户的权限信息 ...

  10. Project Euler Problem 14-Longest Collatz sequence

    记忆化搜索来一发.没想到中间会爆int #include <bits/stdc++.h> using namespace std; const int MAXN = 1000000; in ...