1、使用tinyXml2解析RSS文件,并生成一个网页库pagelib.dat。
tinyXml2 -- https://github.com/leethomason/tinyxml2
rss -- https://coolshell.cn/feed
-- http://www.runoob.com/rss/rss-tutorial.html
正则表达式 进行过滤
参考接口:
struct RssItem { string title; string link; string description; string content; }; class RssReader { public: RssReader(); void parseRss();//解析 void dump(const string & filename);//输出 private: vector_rss; };
要求:最后生成一个 pagelib.txt, 其格式:
1
...
...
...
...
2
...
...
...
...
...
RSS文件解析作业思路:xml -->rss-->tinyxml2(使用该库对rss文件进行解析)--> boost::regex/std::regex(使用正则表达式去除html标签)
提示:首先去读coolshell.xml文件,因为是一个rss文件,而我们需要找到rss的channel节点下面的item节点的title节点、link节点中间的文本,至于这些文本可以使用tinyxml2这个第三方库进行解析,所以这里需要看看timyxml2如何解析第三方库(可以看看timyxml2的源码),解析完成一个item后,可以将其存到vector中(也可以将这些原始信息经过后面正则表达式去除标签后再存起来),然后再去读第二个item(其实就是一个循环 *** 作),其实第二个item是第一个item的兄弟节点(可以使用tinyxml2里面的函数进行跳转到第二个item),这样就可以解析coolshell.xml文档了。接着,因为description信息中包含html的标签,所以需要去除这样的html标签,如
,这个可以使用正则表达式,也就是std::regex进行去除,这个可以在cppreference.html中进行查找使用方法。最后就是遍历vector,讲读取到的信息存到另外一个文件,格式需要自己定义,使用我们自定义的
date_11/13作业总结:
wd老师已把作业实现思路讲的很清楚了,陌生的只是对RSS/HTML不了解,对第三方库tinyxml2的使用不了解,对正则表达式不了解。一开始觉得难,但是去了解了RSS/tinyxml2/正则表达式知识后,才发现,咦,原来不难啊,找到了处理html标签的正则表达式之后,作业基本完成-end.
1.了解RSS语言基本组成:RSS 教程 | 菜鸟教程
2.简单学习tinyxml2库,用于读取xml文件,用XMLElement类里面定义的函数可以获取RSS结点指针,tinyxml2库的安装和学习:参考:https://www.codenong.com/cs106726476/
1.复习:
git clone https://github.com/leethomason/tinyxml2.git
cd tinyxml2/
make
./xmltest
sudo make install
2.把tinyxml2.cpp从github下载,放到自己的项目文件夹3.简单学习XMLdocument类:
1.XMLdocument xml;
xml.LoadFile("coolshell.xml");//1.从当前文件夹读取xml文件2.XMLElement *category = xml.RootElement();//2.拿到根结点rss
3.XMLElement *channel = category->FirstChildElement("channel");//根节点的第一个孩子就是channel
4.XMLElement *title = channel->FirstChildElement("title");//拿到channel的孩子结点title
5.XMLElement *item = channel->FirstChildElement("item");//channel结点有很多个item子结点
//作业的要求就是拿到item结点下的title,link,description,content,存入到结构体中,再用vector保存
item = item->NextSiblingElement();//找下一个兄弟结点item
3.正则表达式处理网页html标签,C++Primer第五版简单了解了下语法,网上找去除html标签的正则表达式,拿来用即可。
1.正则表达式:regex reg("<[^>]*>");
2.regex_replace(str,reg,"")的使用。
代码实现:
01_RssHeader.h
#include#include #include #include "tinyxml2.h" #include using namespace std; using namespace tinyxml2; #include struct RssItem { string title; string link; string description; string content; }; class RssReader { public: RssReader(){}; void parseRss(const char *filename);//1.读取xml文件,解析相应内容,把每个结构体存入vector void read(); //2.把解析的内容输出到控制台 void dump(const string & filename);//3.输出到文件 private: vector _rss; };
02_Rss_main.cc
#include "01_RssHeader.h" int main() { RssReader s1; s1.parseRss("coolshell.xml"); s1.dump("pagelib.dat"); return 0; }
03_parseData.cc
#include "01_RssHeader.h" //获取Rss文件中channel结点下item结点的有用内容:title/link/descirption/content,保存到结构体vector void RssReader::parseRss(const char *filename)//解析 { XMLdocument xml; //1.声明xml类,用来读取xml文件 xml.LoadFile("coolshell.xml");//2.读取xml文件 XMLElement *category = xml.RootElement();//3.拿到xml文件的根节点Rss XMLElement *channel = category->FirstChildElement("channel");//4.拿到channel结点指针 XMLElement *title = channel->FirstChildElement("title"); XMLElement *item = channel->FirstChildElement("item");//5.拿到item结点 while(item)//6.设置循环,遍历channel下的每个item结点 { RssItem rss_item;//7.把数据保存到结构体 regex reg("<[^>]*>"); //8.正则表达式去除网页html标签 //9.获取title结点指针,把内容保存到结构体相应的变量 XMLElement *item_title = item->FirstChildElement("title");//title结点 rss_item.title = item_title->GetText(); //保存结点的内容 //10.获取link结点指针,把内容保存到结构体相应的变量 XMLElement *item_link = item->FirstChildElement("link"); rss_item.link= item_link->GetText(); //cout<FirstChildElement("description"); rss_item.description= item_description->GetText(); rss_item.description = regex_replace(rss_item.description,reg,"");//去除html标签 //11.获取content结点指针,数据用正则去除html标签后,把内容保存到结构体相应的变量 XMLElement *item_content = item->FirstChildElement("content:encoded"); rss_item.content= item_content->GetText(); rss_item.content = regex_replace(rss_item.content,reg,"");//去除网页标签 //12.把每个结构体保存进 vector,每个结构体都是一篇文章了 _rss.push_back(rss_item); item = item->NextSiblingElement();//找下一个item结点 } } void RssReader::read()//内容输出到控制台 { for(int i=0;i<_rss.size();i++) { cout<<_rss[i].title< "<<"n" <<"t"<<" "<"<<"n" <<"t"<<" "<<_rss[i].title<<" "<<"n" <<"t"<<""<<_rss[i].link<<""<<"n" <<"t"<<""<<_rss[i].description<<" "<<"n" <<"t"<<""<<_rss[i].content<<" "<Ubuntu下对代码进行编译:
g++ tinyxml2.cpp 01_RssHeader.h 02_Rss_main.cc 03_parseData.cc -o demo1 -std=c++11
部分输出结果:RSS文件来自Coolshell:Go编程模式 : 泛型编程 | 酷 壳 - CoolShell
1 Go编程模式 : 泛型编程 https://coolshell.cn/articles/21615.htmlGo语言的1.17版本发布了,其中开始正式支持泛型了。虽然还有一些限制(比如,不能把泛型函数export),但是,可以体验了。我的这个《Go编程模式》的系列终于... Read More Read More The post Go编程模式 : 泛型编程 first appeared on 酷 壳 - CoolShell. Go语言的1.17版本发布了,其中开始正式支持泛型了。虽然还有一些限制(比如,不能把泛型函数export),但是,可以体验了。我的这个《Go编程模式》的系列终于有了真正的泛型编程了,再也不需要使用反射或是go generation这些难用的技术了。周末的时候,我把Go 1.17下载下来,然后,体验了一下泛型编程,还是很不错的。下面,就让我们来看一下Go的泛型编程。(注:不过,如果你对泛型编程的重要性还不是很了解的话,你可以先看一下之前的这篇文章《Go编程模式:Go Generation》,然后再读一下《Go编程模式:MapReduce》) 本文是全系列中第10 / 10篇:Go编程模式Go编程模式:切片,接口,时间和性能Go 编程模式:错误处理Go 编程模式:Functional OptionsGo编程模式:委托和反转控制Go编程模式:Map-ReduceGo 编程模式:Go GenerationGo编程模式:修饰器Go编程模式:PipelineGo 编程模式:k8s Visitor 模式Go编程模式 : 泛型编程« 上一篇文章 初探 我们先来看一个简单的示例: package main import "fmt" func print[T any] (arr []T) { for _, v := range arr { fmt.Print(v) fmt.Print(" ") } fmt.Println("") } func main() { strs := []string{"Hello", "World", "Generics"} decs := []float64{3.14, 1.14, 1.618, 2.718 } nums := []int{2,4,6,8} print(strs) print(decs) print(nums) } 上面这个例子中,有一个 print() 函数,这个函数就是想输出数组的值,如果没有泛型的话,这个函数需要写出 int 版,float版,string 版,以及我们的自定义类型(struct)的版本。现在好了,有了泛型的支持后,我们可以使用 [T any] 这样的方式来声明一个泛型类型(有点像C++的 typename T),然后面都使用 T 来声明变量就好。 上面这个示例中,我们泛型的 print() 支持了三种类型的适配—— int型,float64型,和 string型。要让这段程序跑起来需要在编译行上加上 -gcflags=-G=3编译参数(这个编译参数会在1.18版上成为默认参数),如下所示: $ go run -gcflags=-G=3 ./main.go 有了个 *** 作以后,我们就可以写一些标准的算法了,比如,一个查找的算法 func find[T comparable] (arr []T, elem T) int { for i, v := range arr { if v == elem { return i } } return -1 } 我们注意到,我们没有使用 [T any]的形式,而是使用 [T comparable]的形式,comparable是一个接口类型,其约束了我们的类型需要支持 == 的 *** 作, 不然就会有类型不对的编译错误。上面的这个 find() 函数同样可以使用于 int, float64或是string类型。 从上面的这两个小程序来看,Go语言的泛型已基本可用了,只不过,还有三个问题: 一个是 fmt.Printf()中的泛型类型是 %v 还不够好,不能像c++ iostream重载 >> 来获得程序自定义的输出。 另外一个是,go不支持 *** 作符重载,所以,你也很难在泛型算法中使用“泛型 *** 作符”如:== 等 最后一个是,上面的 find() 算法依赖于“数组”,对于hash-table、tree、graph、link等数据结构还要重写。也就是说,没有一个像C++ STL那样的一个泛型迭代器(这其中的一部分工作当然也需要通过重载 *** 作符(如:++ 来实现) 不过,这个已经很好了,让我们来看一下,可以干哪些事了。 数据结构 Stack 栈 编程支持泛型最大的优势就是可以实现类型无关的数据结构了。下面,我们用Slices这个结构体来实现一个Stack的数结构。 首先,我们可以定义一个泛型的Stack type stack [T any] []T 看上去很简单,还是 [T any] ,然后 []T 就是一个数组,接下来就是实现这个数据结构的各种方法了。下面的代码实现了 push() ,pop(),top(),len(),print()这几个方法,这几个方法和 C++的STL中的 Stack很类似。(注:目前Go的泛型函数不支持 export,所以只能使用第一个字符是小写的函数名) func (s *stack[T]) push(elem T) { *s = append(*s, elem) } func (s *stack[T]) pop() { if len(*s) > 0 { *s = (*s)[:len(*s)-1] } } ...... 欢迎分享,转载请注明来源:内存溢出
评论列表(0条)