第一次个人编程作业

GitHub链接 https://github.com/huaku-i/031702147.git

一、前言

就是后悔,非常后悔,真的不懂为啥自己钢铁侠选了C++来写,可能作死吧
但是估计很多人都是用C++写的,想了想我好你好大家好,写个大家都看得懂的版本……QUQ
(这个C++版本只能实现非附加题的问题 看了百度API自动补全 觉得用PY比较好写,
这周末看看用PY 弄一个V2.0版本解决附加题应该会好点
PS:如果评测结果不对 那可能和评测工具不兼容吧

二、个人开发流程(PSP表格)

PSP2.1Personal Software Process Stages预估耗时(分钟)实际耗时(分钟)
* Planning计划1025
Estimate估计这个任务需要多少时间1025
* Development开发500685
Analysis需求分析180120
Design Spec生成设计文档1520
Design Review设计复审1030
Coding Standard代码规范1545
Design具体设计2020
Coding具体编码200240
Code Review代码复审60120
Test测试6090
* Reporting报告6080
Test Repor测试报告3030
Size Measurement计算工作量1010
Postmortem & Process Improvement Plan事后总结, 并提出过程改进计划2040
* total合计570830

三、设计与实现

(1)分析与假设(通过询问,可能这就是面向数据编程我得到了一下几条有用的假设与信息

  • 输入输出都是 UTF8字符编码格式
  • 对于非附加题,第1级,省级行政区:在“XX省”这样的省后缀结尾可能省略“省”,不可能出现缺失
  • 对于非附加题,第2级,地级行政区:在“XX市这样的市后缀结尾”这样的可能省略“市”,同时第二级可能出现缺失
  • 对于非附加题,第3级-第7级地址都可能出现缺失,但不可能出现像前2级那样的省略了(也就是说,只可能省略“省”和“市”这两个字)
  • 假设输入一定是:X!姓名,+地址+电话给出,电话暂定为11位(其实别的位只要连续,也很容易判断)
  • Last but not least 如果我的询问和假设和最终样例出现了偏差…… 那我也没办法QUQ(估计评测当场裂开
    (2)需求与设计
    PS:因为不知道评测提交需要的要求和文件,怕出问题先写到一个CPP里头了
  • 设计流程图:
    1330975-20190917181136693-911651241.png

  • 处理的对象:

名称说明备注
id地址id直辖市1,自治区2,普通省份3
difficult难度分为1!、2!、3!
str主字符串
name名字以逗号分隔
phone电话11位号码
address1第1级地址23个省、5个自治区、4个直辖市、2个特别行政区
address2第2级地址293个地级市、7个地区、30个自治州、3个盟
address3第3级地址963个市辖区、382个县级市、1329个县、117个自治县、49个旗、3个自治旗、1个林区、1个特区
address4第4级地址包括8393个街道、21297个镇、9120个乡、981个民族乡、152个苏木、1个民族苏木、1个县辖区
address5第5级地址路、巷、弄等
address6第6级地址
address7第7级地址其他
other附加
  • 核心函数 :Difficult + Solve +碎碎念

(1)UFT8处理 按顺序来,首先当然是那个UTF8的处理QUQ,这里首先要感谢东哥 一开始没考虑那么多 我用C++写到一半
忽然发现要处理中文字符非常麻烦,本来想直接转PY JAVA了后来东哥抬了我一手 让我知道怎么处理UTF8和Unicode转换

点此查看详细代码 +


//UTF8对应的字符串类型是wstring,其余操作和string一样
//一开始读进来的时候记得用string读入,然后转成UTF8 wstring 处理,最后再转回string输出
string UnicodeToUTF8(const wstring&s) {
string ret;
wstring_convert<codecvt_utf8 > wcv;
ret = wcv.to_bytes(s);
return ret;
}
wstring UTF8ToUnicode(const string &s) {
wstring ret;
wstring_convert<codecvt_utf8 > wcv;
ret = wcv.from_bytes(s);
return ret;
}
text.address1 = L"";//wstring定义时候要加一个L,其他同理

(2)其他string处理函数

点此查看详细代码 +


size_type find( const basic_string &str, size_type index ); //返回str在字符串中第一次出现的位置(从index开始查找),如果没找到则返回string::npos
string &insert(int p,const string &s); //在p位置插入字符串s
string &replace(int p, int n,const char s); //删除从p开始的n个字符,然后在p处插入串s
string &erase(int p, int n); //删除p开始的n个字符,返回修改后的字符串
string substr(int pos = 0,int n = npos) const; //返回pos开始的n个字符组成的字符串
void swap(string &s2); //交换当前字符串与s2的值
string &append(const char
s); //把字符串s连接到当前字符串结尾
void push_back(char c) //当前字符串尾部加一个字符c
const char data()const; //返回一个非null终止的c字符数组,data():与c_str()类似,用于string转const char其中它返回的数组是不以空字符终止,
const char c_str()const; //返回一个以null终止的c字符串,即c_str()函数返回一个指向正规C字符串的指针, 内容与本string串相同,用于string转const char

(3)部分匹配函数代码
第1级:根据汉字匹配

点此查看详细代码 +


int s_address1() {//第一级处理,省级行政区,23个省、5个自治区、4个直辖市
//直辖市1、自治区2、普通省份3(普通省份多特判一个黑龙江)
//判断直辖市
for (int i = 0; i < 4; i++) {
wstring temp = L"";
temp += text.str[0];
temp += text.str[1];
if (temp == special[i]) {
text.address1 = text.str.substr(0, 2);
text.str.erase(0, 2);
if (text.str[0] == L'市')
text.str.erase(0, 1);
return 1;
}
}
//判断自治区
int k = text.str.find(L"自治区");
if (k != text.str.npos) {
text.address1 = text.str.substr(0, k + 2);
text.str.erase(0, k + 2);
return 2;
}
//判断普通省份
if (text.str[0] == L'黑') {//特判黑龙江,因为在普通省份中特字数4个字
if (text.str[3] != L'省') {
text.str.insert(3, L"省");
}
text.address1 = text.str.substr(0, 4);
text.str.erase(0, 4);
return 3;
}
else {
if (text.str[2] != L'省') {
text.str.insert(2, L"省");
}
for (int i = 0; i <= 2; i++)
text.address1 += text.str[i];
text.str.erase(0, 3);
return 3;
}
return 0;//第一级不可能缺失,除了附加题
}

第2级直接本地打表,暴力匹配+补全

点此查看详细代码 +


void s_address2() {
//第二级处理,293个地级市、7个地区、30个自治州、3个盟,(有时候会出现缺失,因此需要匹配操作)
//市、自治州
if (text.id == 1) {//直辖市特判
text.address2 = text.address1 + L"市";
return;
}
else{//其他省份
int k = text.str.find(L"盟");
if (k != text.str.npos) {
text.address2 = text.str.substr(0, k + 1);
text.str.erase(0, k + 1);
return;
}
k = text.str.find(L"自治州");
if (k != text.str.npos) {
text.address2 = text.str.substr(0, k + 3);
text.str.erase(0, k + 3);
return;
}
for (int i = 0; i <= 332; i++) {//地级市(可能会省略“市”,所以要补齐操作)//自治州、盟、地区、
if (text.str.find(city[i]) ==0) {
int k = city[i].length();
text.str.insert(k, L"市");
text.address2 = text.str.substr(0, k + 1);
text.str.erase(0, k + 1);
if (text.str[0] == L'市')
text.str.erase(0, 1);
return;
}
}
}
text.address2 = L"";//全部都没找到就为第二级全部缺失
return;
}

第3级-第7级暴力识别匹配

(4)主解决函数

点此查看详细代码 +


void solve(string s) {
text.str = UTF8ToUnicode(s);//转码
if (text.str[0] == L'0')text.difficult = 0;
if (text.str[0] == L'1')text.difficult = 1;
if (text.str[0] == L'2')text.difficult = 2;
text.str.erase(0, 2);
int len = text.str.length();
text.str.erase(len - 1, 1);//处理前缀后缀英文句点,难度信息
s_phone();
s_name();
text.id = s_address1();
s_address2();
s_address3();
s_address4();
s_address5();
s_address6();
s_address7();

}

说实话V1.0有点暴力 ……其余就不一一列出了,核心思想就是匹配查找+字符串切割、更新

四、性能改进

1330975-20190917181739424-27367387.png
1330975-20190917182302362-482827076.png
1330975-20190917182017317-1738978353.png
查找对比了一下突然发现主要耗时在转码和读入输出上OTL ,当然匹配也花费了一些时间OTL
重新修改了一下 匹配用了KMP(虽然查找匹配量不大的话可能不太明显?)
同时优化了一下异常处理和输出JSON函数(GAN 最后C++还是得手敲轮子)QUQ

五、单元测试

构造了4个函数address_plus1()、address_plus2()、address_phone()、address_name()进行单元测试比对
同时也想了特殊EXAMPLE:
1330975-20190917183514299-1526027775.png
1330975-20190917183536250-926728094.png
更过分的是……
1330975-20190917183641860-308251231.png凶残的不讲道理
询问福哥正确性+自己查了一下后
得出

  • 一级行政区省级行政区34个:23个省、5个自治区、4个直辖市、2个特别行政区;
  • 二级行政区地级行政区333个:293个地级市、7个地区、30个自治州、3个盟。
  • 三级行政区县级行政区2845个:963个市辖区、382个县级市、1329个县、117个自治县、49个旗、3个自治旗、1个林区、1个特区。(截止2019年9月)
  • 四级行政区乡级行政区39945个:包括8393个街道、21297个镇、9120个乡、981个民族乡、152个苏木、1个民族苏木、1个县辖区。(截止2018年底)
    同时构造了如下数据检测覆盖率,进行单元测试
    部分特殊input:
2!张三,湖北省随州随县吴山镇唐王街联宏村18883549874委会.
2!李四,福建省福州13756899511市鼓楼区鼓西街道湖滨路110号湖滨大厦一层.
1!王五,福建福州闽13599622362侯县上街镇福州大学10#111.
2!红太狼,福建省福州市鼓楼18960221533区五一北路123号福州鼓楼医院.
1!灰太狼,广东省东莞市凤岗13965231525镇凤平路13号.
2!喜羊羊,云南省湘西土家族苗族自治州13965231525香格里拉市福州路10#112.
1!小张,福建省福州市福清市龙江18150632336街道福山路43号中银公寓.
2!小明,福18150632336建福州福清福山路43号.
1!小洪,陕西省铜川18150632336福州路22号.
2!小王,陕西铜川18150632336.
2!小郑,福建.

相对output:

[{"地址":["湖北省","随州市","随县","吴山镇","唐王街","","联宏村委会"],"姓名":"张三","手机":"18883549874"},
{"地址":["福建省","福州市","鼓楼区","鼓西街道","湖滨路","110号","湖滨大厦一层"],"姓名":"李四","手机":"13756899511"},
{"地址":["福建省","福州市","闽侯县","上街镇","福州大学10#111"],"姓名":"王五","手机":"13599622362"},
{"地址":["福建省","福州市","鼓楼区","","五一北路","123号","福州鼓楼医院"],"姓名":"红太狼","手机":"18960221533"},
{"地址":["广东省","东莞市","","凤岗镇","凤平路13号"],"姓名":"灰太狼","手机":"13965231525"},
{"地址":["云南省","湘西土家族苗族自治州","香格里拉市","","福州路","","10#112"],"姓名":"喜羊羊","手机":"13965231525"},
{"地址":["福建省","福州市","福清市","龙江街道","福山路43号中银公寓"],"姓名":"小张","手机":"18150632336"},
{"地址":["福建省","福州市","","","福清福山路","43号",""],"姓名":"小明","手机":"18150632336"},
{"地址":["陕西省","铜川市","","","福州路22号"],"姓名":"小洪","手机":"18150632336"},
{"地址":["陕西省","铜川市","","","","",""],"姓名":"小王","手机":"18150632336"},
{"地址":["福建省","","","","","",""],"姓名":"小郑","手机":""}]

六、异常处理

  • 处理对输入为空时的警告输出
 if (text.str == L"")
            fout << "input error!" << endl;
  • 处理了输入不为UTF8时的警告输出
if (text.str[0] != L"1"||text.str[0] != L"2"||text.str[0] != L"3")
            fout << "string error!" << endl;
  • 同时也增加了对输入警告错误输出
        if (text.name == L"")
            fout << "name error!" << endl;
    if (text.phone == L"")
            fout << "phone error!" << endl;

对于匹配不到11位(暂定)的电话号码和识别不到姓名的异常情况会输出错误

七、ENDING(碎碎念)

  • 一开始是想到用PY写的……但是题目不让我用、
    开始写了之后吧……… 又改题目让用了
  • 输入输出格式一开始没那么多规定……写着写着,变UTF8了……(虽然说不改中文字符也过不去)本来想GG半路上华一大佬的py贼船了,又狠不下写了一半的代码
  • 问题解决了、、写的差不多了……才发现一些神奇的地区和设定问题,于是又自闭踏上了DEBUG和优化的漫漫路
  • 都做完了 才发现这评测工具无教程只有命令行 (甚至像病毒)才是最难的OTL,C++手造轮子 基本没队友+没人权=自闭……
  • 其实也是可以用正则匹配的,不过想了想反正都要打表匹配补全,还不如直接全暴力处理了主要函数都类似改起来也快0.0
    又碰上事情多的一周 当场裂开(满脸心酸.jpg 被自己菜哭)

转载于:https://www.cnblogs.com/huakui/p/11535127.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值