C++封装html实体编码转换

起源:在匹配网页中的关键词的时候,发现网页中存在某个目标关键词,但是没有成功匹配出来。经分析发现网页中的关键词是以html实体编码的方式存在的,所以封装一下html实体编码与正常文本之间的转换,也给其他遇到这种问题的朋友们一个参考。

举例:“免费”与“免费”之间的转换

转换过程:

  • html实体编码转换为正常文本
    • 逐个读取出目标文本中的html实体编码,这算是一个“免”
    • 先转换为unicode字符串:\u514D
    • 再转为汉字:免
  • 正常文本转换为html实体编码
    • 逐个取出目标文本中的字,一个汉字算一个字,一个英文字符也算是一个字,一个数字也算是一个字
    • 对每个字先转为unicode字符串
    • 再由unicode字符串转为html实体编码

#pragma once
#include <string>
#include <boost/locale.hpp>


namespace HtmlEscape {
	std::string html_escape(std::string str);
	std::string html_unescape(std::string str);
	
	std::string ustr_word_to_char(std::string ustr);
	std::string char_word_to_ustr(std::string str_char);
	std::string ustr_word_to_html(std::string ustr);
	std::string html_word_to_ustr(std::string html_str);
}
// html实体编码 解码为 正常文本字符  最终输出为GBK编码
std::string HtmlEscape::html_unescape(std::string html_str) {
	std::string text = html_str;
	size_t npos = 0;
	while (npos < text.length() - 3) {
		if (text[npos] == '&' && text[npos + 1] == '#') {
			size_t nend = npos + 2;
			while (nend < text.length()) {
				if (text[nend] >= '0' && text[nend] <= '9') nend++;
				else if (text[nend] == ';') break;
				else break;
			}

			if (text[nend] == ';') {
				// 到这里说明定位到一个html实体编码
				std::string html_word = text.substr(npos, nend - npos + 1);
				std::string uword = HtmlEscape::html_word_to_ustr(html_word);
				std::string sword = HtmlEscape::ustr_word_to_char(uword);
				// printf("%s -> %s\n", html_word.c_str(), sword.c_str());
				if (sword.length() > 0) {
					// 替换文本中的html实体编码
					std::string tmp = text.substr(0, npos);
					tmp += sword;
					tmp += text.substr(nend + 1);
					text = tmp;
				}
			}
		}
		npos += 1;
	}
	return text;


// 	std::string str_charset = "";
// 	if (charset == HtmlEncode_GBK) str_charset = "gbk";
// 	else if (charset == HtmlEncode_UTF8) str_charset = "utf-8";
// 	else return "";
// 
// 	size_t nstart = 0, npos = 0;
// 	while (true) {
// 		// 定位查找一个html实体编码
// 		npos = str.find("&#", nstart);
// 		if (npos == std::string::npos) break;
// 		size_t nend = npos + 2;
// 		while (nend < str.length() && str[nend] >= '0' && str[nend] <= '9') nend += 1;
// 
// 		// 定位到一个html实体编码
// 		if (nend < str.length() && str[nend] == ';') {
// 			char loginfo[1024] = { 0 };
// 			// 当前实体编码中的数值
// 			int html_code_num = atoi(str.substr(npos + 2, nend - npos - 2).c_str());
// 			sprintf(loginfo, "%d", html_code_num);
// 			// 数值转Unicode字符串
// 			std::string charArr = "0123456789ABCDEF";
// 			std::string unicode_str = "";
// 			while (true) {
// 				if (html_code_num < 15) { unicode_str = charArr[html_code_num] + unicode_str; break; }
// 				else {
// 					int yushu = html_code_num % 16;
// 					html_code_num = html_code_num / 16;
// 
// 					unicode_str = charArr[yushu] + unicode_str;
// 				}
// 			}
// 			sprintf(loginfo, "%s %s", loginfo, unicode_str.c_str());
// 			// Unicode字符串 转 文本字符
// 			std::string sword = HtmlEscape::ustr_word_to_char(unicode_str);
// 			sprintf(loginfo, "%s %s", loginfo, sword.c_str());
// 			// printf("%s\n", loginfo);
// 
// 			// 获取到的文本字符 更新到字符串中
// 			std::string tmp = str.substr(0, npos);
// 			tmp += sword;
// 			tmp += str.substr(nend + 1);
// 			str = tmp;
// 		}
// 		else nstart = npos + 2;
// 	}
// 	return str;
}
// 正常文本字符 转码为 html实体编码  输入文本为GBK编码
std::string HtmlEscape::html_escape(std::string str) {
	std::string html_str = "";
	for (size_t i = 0; i < str.length(); i++) {
		int byte_num;
		if ((unsigned char)str[i] <= 0x80) byte_num = 1;
		else byte_num = 2;

		std::string sword = str.substr(i, byte_num);
		std::string uword = HtmlEscape::char_word_to_ustr(sword);
		std::string html_word = HtmlEscape::ustr_word_to_html(uword);
		i += (byte_num - 1);

		if (html_word.length() > 0) html_str += html_word;
		else html_str += sword;
	}

	return html_str;
}

// 只处理一个字 \u514D  转为  “免”	(输出结果为GBK编码)
std::string HtmlEscape::ustr_word_to_char(std::string ustr) {
	std::wstring wstr;
	if (ustr.substr(0, 2) == "\\u") ustr = ustr.substr(2);
	if (ustr.length() == 0) return "";
	wchar_t ws[2] = { 0 }; ws[0] = strtol(ustr.c_str(), NULL, 16);
	std::string char_str = boost::locale::conv::from_utf(ws, "GBK");

	return char_str;
}
// 只处理一个字 “免”  转为  \u514D	(传入值为GBK编码)
std::string HtmlEscape::char_word_to_ustr(std::string str_char) {
	std::string ustr = "";
	std::wstring wstr = boost::locale::conv::to_utf<wchar_t>(str_char, "GBK");
	for (size_t i = 0; i < wstr.length() * sizeof(wchar_t); i++) {
		char tmp[5] = { 0 };
		sprintf(tmp, "%X", *((unsigned char*)wstr.c_str() + i));
		ustr = tmp + ustr;
	}
	ustr = "\\u" + ustr;
	return ustr;
}
// Unicode字符串 转 html实体编码	\u514D 转 &#20813;
std::string HtmlEscape::ustr_word_to_html(std::string ustr) {
	if (ustr.substr(0, 2) == "\\u") ustr = ustr.substr(2);

	int unicode_num = stoul(ustr, 0, 16);
	/*
	// 下面是stoul的实现
	std::string charArr = "0123456789ABCDEF";
	int html_code_num = 0;
	for (int i = 0; i < unicode_str.length(); i++) {
		char ch = unicode_str[unicode_str.length() - i - 1];
		int num = 0;
		while (num < charArr.length() && charArr[num] != ch) num++;

		html_code_num += (num*pow(16, i));
	}
	*/

	char tmp[10] = { 0 }; sprintf(tmp, "&#%d;", unicode_num);
	std::string html_word = tmp;
	return html_word;
}
// html实体编码 转 Unicode字符串	&#20813; 转 \u514D
std::string HtmlEscape::html_word_to_ustr(std::string html_str) {
	if (html_str.length() <= 3 || html_str.substr(0, 2) != "&#" || html_str[html_str.length() - 1] != ';') return "";
	for (size_t i = 2; i < html_str.length() - 1; i++) {
		if (html_str[i] < '0' || html_str[i] > '9') return "";
	}
	// 到这里确认当前html实体编码是正确格式

	int html_word_num = atoi(html_str.substr(2, html_str.length() - 1 - 2).c_str());

	std::string charArr = "0123456789ABCDEF";
	std::string unicode_str = "";
	while (true) {
		if (html_word_num < 15) { unicode_str = charArr[html_word_num] + unicode_str; break; }
		else {
			int yushu = html_word_num % 16;
			html_word_num = html_word_num / 16;

			unicode_str = charArr[yushu] + unicode_str;
		}
	}
	unicode_str = "\\u" + unicode_str;
	return unicode_str;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值