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

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. thinkphp5.0 composer安装phpmailer

    1.安装:composer require phpmailer/phpmailer 2.引入:use PHPMailer\PHPMailer\PHPMailer: 3.调用:$mail = new P ...

  2. Hibernate错误——No row with the given identifier exists

    错误 是用的是Hibernate自动建立的数据表,在进行数据库操作时,出现错误No row with the given identifier exists 解决 关系数据库一致性遭到了破坏,找到相关 ...

  3. celery琐碎笔记

    -l 指定日志等级 -n 指定任务名称 -Q 指定任务执行队列 -c 指定启动celery的cpu数量 --logfile 指定日志输出到文件,会输出任务函数里的print,而控制台不会,用于调试. ...

  4. vue页面内监听路由变化

    beforeRouteEnter (to, from, next) { // 在渲染该组件的对应路由被 confirm 前调用 // 不!能!获取组件实例 `this` // 因为当钩子执行前,组件实 ...

  5. react 问题记录

    1.控制台报错: Uncaught Error: addComponentAsRefTo(...): Only a ReactOwner can have refs. You might be add ...

  6. Open Source GIS and Freeware GIS Applications

    Open Source GIS and Freeware GIS Applications   An open source application by definition is software ...

  7. vue-awesome-swiper轮播插件的使用方法及问题。

    在使用vue-awesome-swiper的时候,遇到一些问题,记录一下!       1.npm 安装 npm install vue-awesome-swiper --save 2.使用 在mai ...

  8. tensorflow入门——3解决问题——4让我们开始吧

    深度学习适合解决海量数据和复杂问题 在机器学习中,语音识别,图像识别,语意识别用的是不同的技术,从事相关工作的人合作几乎不可能. 深度学习改变了这一切. 80年代计算机很慢,数据集很小,因此深度学习没 ...

  9. HDU 2066最短路径Dijkstra、

    思路:枚举所有起点城市然后比较每个起点所去喜欢城市的最小距离 #include<cstdio> #include<cmath> #include<cstring> ...

  10. centos7.0 可以访问HTML文件,不能访问PHP文件,因为php-fpm没有扩展包

    解决方法 :https://blog.csdn.net/ityang_/article/details/53980190 nginx调用PHP有sock方式和端口方式 1.确认nginx已经调用了ph ...