OOP-THU
OOP-THU copied to clipboard
L12笔记
L12笔记
ppt中讲的比较清楚或者比较容易的内容就不再作为重点了,主要挑一些我觉得比较难理解的来记。
string类
-
string s2(s0, 8, 3); //截取,index从8开始,长度为3。这实际上跟substr实现了一样的功能,是可以记住的两种截取方式。用法上,除了参数列表多了个s0, 跟substr也没有什么区别。
-
string s4(10, 'x'); //复制字符:xxxxxxxxxx
-
str.c_str() //注意返回值为常量字符指针(const char*),不能修改。
-
清空:clear()。
-
查询长度:size()或者length() 。
-
尾部添加有两种:push_back()和append() ,当然也可以直接+=或者+。
-
比较:字典序。C++的字典序:比较第一个不一样的字符。跟长度不一定有关系。比如aaaa<av。
-
一个试水案例:
#include <iostream> using namespace std; int main(){ string str; cout<<str.empty()<<endl;//1 cin>>str; cout<<str.empty()<<endl;//0 for(char c: str){//跟vector类似的用法 cout<<c; } cout<<endl; str.clear(); cout<<str.empty()<<endl;//1 }
-
p10的解释:
int b = stoi("50 cats", &sz)
自动找到string中可以转成数字的那些东西
(其实是非数字的字符前面的那些数字字符)
开头是数字字符时才能直接用这个
S表示string;
i,d,f表示目标的类型
-
输入方式
直接cin:读取可见字符 到空格。
-
Getline(cin, str); :读取一行,以换行符判断。
-
Getline(cin, str, '#'); :读到指定分隔符为止,这个分隔符可以任选。
-
***注意,字符串里面可以有换行符(作为元素)
-
补充一些输入相关:
-
#include <iostream> #include <string> #include <cctype> #include <fstream> using namespace std; int main(){ // string str; // str=cin.get(); // cout<<str<<endl;//1,只能拿到一位。 char a[15]; cin.get(a, 10);//2 拿到10位 }
-
IOstream
-
Istream, ostream都是类,cin, cout是类的对象。
-
头文件中只有cin和cout对象 -
ostream:重载了针对基础类型(内嵌类型)的输出流运算符(<<), 接受不同类型的数据,再调用系统函数进行输出
-
每次输出运算都要返回对象的引用
-
格式化输出:include
。 -
cout << fixed << 2018.0 << " " << 0.0001 << endl; //浮点数 -> 2018.000000 0.000100 6位 cout << scientific << 2018.0 << " " << 0.0001 << endl; //科学计数法 -> 2.018000e+03 1.000000e-04 cout << defaultfloat; //还原默认输出格式 cout << setprecision(2) << 3.1415926 << endl; //输出精度设置为2 -> 3.1 cout << oct << 12 << " " << hex << 12 << endl; //八进制输出 -> 14 十六进制输出 -> c cout << dec; //还原十进制 cout << setw(3) << setfill('*') << 5 << endl; //设置对齐长度为3,对齐长度所需填充的字符为* -> **5
-
上面是课件内容。fixed、scientific、defaultfloat、oct、hex、dec是流操作算子。补充一点较常用的steprecision:
-
-- precision是成员函数,其调用方式为:cout.precition(5); -- setprecision是流操作算子,其调用方式为:cout << setprecision(5); // 可以连续输出 即是连续起作用,设置一个之后,后面其他浮点数都按照这个格式输出 它们的功能相同。 指定输出浮点数的有效位数(非定点方式输出时) 指定输出浮点数的小数点后的有效位数(定点方式输出时) 定点方式:小数点必须出现在个位数后面 非定点方式:小数点不在个位数后面 例如科学计数法
-
自定义流操纵算子,如:
-
eg: ostream& tab(ostream& output) { return output << '\t'; } // 函数可以交给cout用于输出,称作流操纵算子 // 为什么可以把函数名字写在cout输入语句? // 因为iostream里对 << 进行了重载(成员函数) // ostream& operator<< (ostream& (*p)(ostream&)); // 函数指针 // 该函数内部会调用p所指向的函数,且*this作为参数 hex, dec, oct都是函数 cout << "aa" << tab << "bb" << endl;
-
endl:是一个函数,等同于输出'\n',再清空缓冲区 os.flush()。
-
重载流运算符总是返回引用,禁止复制,只能移动。全局只有cout一个对象(减少复制开销,符合oop思想)。
文件流
ifstream是istream的子类,功能是从文件中读入数据。(不能写出)
打开文件的三种方式:
ifstream ifs("input.txt"); ifstream ifs("binary.bin", ifstream::binary);//以二进制形式打开文件 ifstream ifs; ifs.open("file");//do something ifs.close();
p26读入示例的解释:
-
ws:用于在输入时跳过开头的空白符 。
-
EOF:EOF是end of file的缩写,表示”文字流”(stream)的结尾。这里的”文字流”,可以是文件(file),也可以是标准输入(stdin)。 EOF不是特殊字符,而是一个定义在头文件stdio.h的常量,一般等于-1。#define EOF (-1) 除了表示文件结尾,EOF还可以表示标准输入的结尾。但是,标准输入与文件不一样,无法事先知道输入的长度,必须手动输入一个字符,表示到达EOF (转自https://blog.csdn.net/sinat_36053757/article/details/66546610)
-
字符串输入输出流
stringstream是iostream子类,后者又是i和ostream的子类。所以stringstream继承了双方的接口。
-
它在对象内部维护了一个buffer,使用流输出函数可以将数据写入buffer,使用流输入函数可以从buffer中读出数据。
-
程序内部的字符串操作。
-
int main() { stringstream ss; ss << "10"; ss << "0 200"; int a, b; ss >> a >> b; //a=100 b=200 return 0; } //这里主要是体现了buffer在结合上<<, >>之后的用途 //先把“10”和“0 200”用<<放进来,这样buffer里面是这样:100 200 //然后再用>>把buffer里面的内容放进去,由于指定了读法:两个int,所以就和先后输入100和200一样了。 //可以连接字符串,可以将字符串转换为其他类型的数据
-
p33解释:从tail开始读。head** 是等待读入的最后位置**(还没有读过的在开头;已经读过的在尾巴)head到tail表示当前等待读入的缓冲区,所以head在后面。
-
函数模板:convert<目标类型>( ) 可以代替std::to_string 和atoi, stoi.
-
//ppt p35 template<class outtype, class intype> outtype convert(intype val) { static stringstream ss; //使用静态变量避免重复初始化 ss.str(""); //清空缓冲区 ss.clear(); //清空状态位(不是清空内容) //https://blog.csdn.net/clearriver/article/details/4366872 ss << val; //把intype类的输入量放进缓冲区 outtype res; //先定义一个接收器 ss >> res; //把缓冲区里的东西放进接收器。这个过程跟outtype的具体类型有关。 return res; }
字符串处理和正则表达式
-
正则表达式的定义:由字母和符号组成的特殊文本,搜索文本时定义的一种规则
-
-
中括号:内部的东西是允许出现的
大括号:长度范围要求
-
三种模式:匹配,搜索,替换。
-
指定某个字符,可以在字符串里找到所有的该字符。例如the,使用the进行搜索,可以找到句中所有的"the"。
-
用法和格式:
-
[a-z] 匹配所有单个小写字母。
-
**[0-9]**匹配所有单个数字。
-
**[a-z] [0-9]**匹配所有字母数字的组合。
-
**[ab] c **匹配ac或者bc。例如:•[Tt]he: The car parked in the garage.
- 推广来说,前面特殊(如[], . ,等等有特殊意义的表示)+后面一般(就是单纯的几个字符,没有任何形式的括号等)这个模式经常会用。例如[Tt]ree, .ar ......
- 当然也可以是前面一般后面特殊。ge\ .
-
**\d **等于[0-9].
-
\w 等于**[a-zA-Z0-9_]**,大小写字母,数字,下滑线的组合。
-
. 匹配换行外的全部字符。
-
\ . 匹配句号。
-
[ ^ a-z] 匹配所有非小写字母的单个字符.
-
\D 等价[ ^ 0-9 ], 匹配所有单个非数字.
-
\s 匹配所有空白字符,如\t,\n
-
\S 匹配所有非空白字符
-
\W 匹配非字母、数字、下划线。
-
^后面紧跟着的是开头,^\t只能匹配到以制表符开头的内容。
-
? 出现0次或1次
-
+至少连续出现1次及以上
-
*至少连续出现0次及以上
-
重复模式:
-
**x{n,m}**代表前面内容出现次数重复n~m次。m若为空则表示没有上限。按照个人尝试的结果,n不可以为空。
-
+前一个字符至少连续出现1次及以上。比如a\w+: The car parked in the garage
-
扩展:[a-z] {5, 12}长度为5~12的英文字母组合; .{5}所有长度为5的。
-
-
-
怎么用?先要引入
. -
创建正则表达式:regex re("^[1-9][0-9]{10}$")
这就是 第一位非0 其他是0-9
创造方法:括号里面一个字符串。字符串是目标表达式。
-
如果需要创建正则表达式"\d+",应该写成regex re("\ \d+")。因为\是转义字符。
-
使用原生字符串可以保留字面值,取消转义: R"(str)".
- 括号里面是字符串,外面是个引号。
- •"\d+" = R"(\d+)" = \d+
- 可以换行。
- R这个符号不光可以用在regex中。实际上它本身是对string做操作的。仅用在string上当然也可以。
-
匹配:•regex_match(s, re):询问字符串s是否能完全匹配正则表达式re。注意此处s自然是string类,而re是regex类的。
-
//自行试水 #include <iostream> #include <string> #include <regex> using namespace std; int main() { string s("student"); regex e("stu.*"); //.匹配换行符以外任意符号 //*任意长度 if(regex_match(s,e)) cout << "matched" << endl; //another regex string str; cin>>str; regex new_e(R"(^[a-z0-9_]{3,15}$)"); if(regex_match(str,new_e)) cout << "matched" << endl; } //注意到单纯以匹配为目的时,smatch sm这句话不是必要的。
-
捕获和分组:有时我们需要知道正则式的某一部分匹配了字符串的哪一部分。
-
使用()进行标识,每个标识的内容被称作分组。
-
regex_match(s, result, re):询问字符串s是否能完全匹配正则表达式re,并将捕获结果储存到result中。re是regex类的对象,result是smatch类型的对象。
-
如果需要括号,又不想捕获该分组,可以使用(?:pattern)
用(?:sub)(.*)匹配subject:0号为subject,1号为ject
这样sub就不捕获了。
-
分组按顺序编号:
•0号永远是匹配的字符串本身
•(a)(pple): 0号为apple,1号为a,2号为pple
•用(sub)(.*)匹配subject:0号为subject,1号为sub,2号为ject
就是说,括号里面的匹配都是1+号匹配。
-
//ppt示例 int main () { string s("version10"); regex e(R"(version(\d+))"); smatch sm; if(regex_match(s,sm,e)) { cout << sm.size() << " matches\n"; cout << "the matches were:" << endl; for (unsigned i=0; i<sm.size(); ++i) { cout << sm[i] << endl; } } return 0; } //结果:2 matches //the matches were: //version10 //10 //一些解释 //R"(version(\d+))"==" version(\d+)"其实只有一个括号,那个R自带的括号可以认为是假括号。 //这里有两个匹配,0号匹配匹配整个字符串,匹配结果是version10;1号匹配是那个内部括号,匹配结果是10 //regex_match(s,sm,e) //将匹配结果都放到了sm里面
-
-
搜索
-
regex_search(s, result, re):搜索字符串s中能够匹配正则表达式re的第一个子串,并将结果存储在result中。result照例还是smatch对象。
-
分组同样会被捕获。
-
//ppt示例,带有自己的批注 #include <iostream> #include <string> #include <regex> using namespace std; int main() { string s("this subject has a submarine"); regex e(R"((sub)([\S]*))"); //正则表达式是:(sub)([\S]*) smatch sm; //每次搜索时当仅保存第一个匹配到的子串 while(regex_search(s,sm,e)){ for (unsigned i=0; i<sm.size(); ++i) cout << "[" << sm[i] << "] "; cout << endl; s = sm.suffix().str(); //Suffix是把sm后面的子串传到s里面(也就是,不再有前面已搜索过的子串。这样可以不重复 } return 0; }
-
-
替换
-
regex_replace(s, re, s1):替换字符串s中所有匹配正则表达式re的子串,并替换成s1(字符串类型)。
-
regex_replace返回值即为替换后的字符串。不过要注意一开始的那个字符串s并没有变。
-
#include <iostream> #include <string> #include <regex> using namespace std; //ppt样例 int main() { string s("this subject has a submarine"); regex e(R"(sub[\S]*)"); //表达式为sub[\S]* //regex_replace返回值即为替换后的字符串 cout << regex_replace(s,e,"SUB") << "\n"; cout<<s<<endl; //this SUB has a SUB //this subject has a submarine //s没有变。 return 0; }
-
#include <iostream> #include <string> #include <regex> using namespace std; //ppt样例 int main() { string s("this subject has a submarine"); regex e(R"((sub)([\S]*))"); //表达式:(sub)([\S]*) //regex_replace返回值即为替换后的字符串 cout << regex_replace(s,e,"SUBJECT") << endl; //$&表示所有匹配成功的部分,[$&]表示将其用[]括起来 cout << regex_replace(s,e,"[$&]") << endl; //$i输出e中第i个括号匹配到的值 cout << regex_replace(s,e,"$1") << endl; cout << regex_replace(s,e,"$2") << endl; cout << regex_replace(s,e,"$1 and [$2]") << endl; return 0; } //this SUBJECT has a SUBJECT //this [subject] has a [submarine] //this sub has a sub //this ject has a marine //this sub and [ject] has a sub and [marine]
-
可以看出,捕获的分组还是存贮了的。
-
$& 代表re匹配的所有子串
$1, $2 代表re匹配的第1/2个分组
-
-
-
学生信息例题的一些解释
-
注意在正则表达式中使用|符合来表达“或者”
第一个表达式:(My name is |I am )(\w+).
0——整个;1——My name is |I am ;2——\w+
第二个表达式:(\d{4}) [.-] (\d{1,2}) [.-] (\d{1,2})
0——整个;1——\d{4};2——\d{1,2};3——同2
第三个表达式:[1-9]\d{10}
0——整个
第四个表达式也没有括号,和3一样。
-
我们去年已经有同学整理过笔记 https://github.com/thunlp/OOP-THU/issues/47 如果只是重复课上内容可能贡献不大,大家可能也不太想看到重复内容。如果有新增部分,欢迎对之前的笔记做一定的补充。