吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 1320|回复: 19
收起左侧

[C&C++ 原创] 基于C++的业余无线电呼号查询工具

  [复制链接]
bgwu666 发表于 2024-9-30 22:28
本帖最后由 bgwu666 于 2024-9-30 22:30 编辑

前言

自从接触业余无线电后,就会对见到的每个呼号都产生好奇心,总想查一查这些HAM呼号的QTH。网络上的QTH查询工具需要呼号所有者自行上传位置,而没上传的自然就查不到,于是萌生了自己写一个查询工具的想法,查到具体省份即可。

该工具依据业余无线电台呼号管理办法,基于C++所写,为初学练手项目,如有不足,恳请批评指正:Goal75KG/CallSignQuery

功能

  • 根据呼号解析出国家信息(暂时只能解析中国)
  • 查询电台种类(个人业余电台、信标台、卫星电台等)
  • 确定呼号所属省份
  • 处理特殊情况的电台种类

示例

输入呼号:BA8MAA

输出结果:

呼号: BA8MAA
国家: 中国
电台种类: 个人业余电台(一级)
省份: 贵州

实现过程

映射呼号每部分规则

// 加载国家前缀规则
std::map<std::string, std::string> loadCountryPrefixRules() {
    std::map<std::string, std::string> countryPrefixRules;
    countryPrefixRules["B"] = "中国";
    return countryPrefixRules;

// 加载电台种类规则
std::map<char, std::string> loadStationTypeRules() {
    std::map<char, std::string> stationTypeRules;
    stationTypeRules['A'] = "个人业余电台(一级)";
    stationTypeRules['D'] = "个人业余电台(二级)";
    stationTypeRules['E'] = "个人业余电台(二级)";
    stationTypeRules['G'] = "个人业余电台(三级、四级、五级(收信台))";
    stationTypeRules['H'] = "个人业余电台(三级、四级、五级(收信台))";
    stationTypeRules['I'] = "个人业余电台(三级、四级、五级(收信台))";
    stationTypeRules['J'] = "业余信标台";
    stationTypeRules['L'] = "外籍及香港、澳门、台湾地区人员在中国内地设置的业余电台";
    stationTypeRules['R'] = "业余中继台";
    stationTypeRules['T'] = "特设业余电台";
    stationTypeRules['Y'] = "集体业余电台";
    return stationTypeRules;
}

// 加载电台种类规则
std::map<char, std::string> loadStationTypeRules() {
    std::map<char, std::string> stationTypeRules;
    stationTypeRules['A'] = "个人业余电台(一级)";
    stationTypeRules['D'] = "个人业余电台(二级)";
    stationTypeRules['E'] = "个人业余电台(二级)";
    stationTypeRules['G'] = "个人业余电台(三级、四级、五级(收信台))";
    stationTypeRules['H'] = "个人业余电台(三级、四级、五级(收信台))";
    stationTypeRules['I'] = "个人业余电台(三级、四级、五级(收信台))";
    stationTypeRules['J'] = "业余信标台";
    stationTypeRules['L'] = "外籍及香港、澳门、台湾地区人员在中国内地设置的业余电台";
    stationTypeRules['R'] = "业余中继台";
    stationTypeRules['T'] = "特设业余电台";
    stationTypeRules['Y'] = "集体业余电台";
    return stationTypeRules;
}

判断对应后缀是否在范围内

bool isWithinRange(const std::string &suffix, const std::string &rangeStart, const std::string &rangeEnd) {
    return suffix >= rangeStart && suffix <= rangeEnd;
}

呼号匹配

void queryCallSign(const std::string &callSign) {
    // 加载各类规则
    auto countryRules = loadCountryPrefixRules();
    auto stationTypeRules = loadStationTypeRules();
    auto regionProvinceRules = loadRegionProvinceRules();

    // 确保呼号至少有5位
    if (callSign.length() < 5) {
        std::cout << "呼号格式不正确" << std::endl;
        return;
    }

    // 解析国家前缀
    std::string country = countryRules[callSign.substr(0, 1)];

    // 解析电台种类
    char stationType = callSign[1];
    std::string station = stationTypeRules[stationType];

    // 解析地区分区
    char region = callSign[2];

    // 解析后缀
    std::string suffix = callSign.substr(3, 2); // 假设后缀长度为2位

    // 查找该地区的省份范围
    std::string provinceName = "未知省份";
    if (regionProvinceRules.find(region) != regionProvinceRules.end()) {
        for (const auto &province: regionProvinceRules[region]) {
            if (isWithinRange(suffix, province.second.first, province.second.second)) {
                provinceName = province.first;
                break;
            }
        }
    }

处理特殊情况(业余信标台、卫星业余电台、特设业余电台)

if (stationType == 'J') {
        char suffix1 = callSign[3];
        if (suffix1 == 'H' || suffix1 == 'V' || suffix1 == 'U') {
            station = "HF、VHF、UHV频段信标台";
        } else if (suffix1 == 'D') {
            station = "业余无线电测向专用信标台";
        } else if (suffix1 == 'S' && region == '1') {
            station = "卫星业余电台";
        } else if (suffix1 == 'T') {
            station = "特设业余电台";
        }
    }

结果输出

    if (!country.empty() && !station.empty() && provinceName != "未知省份") {
        std::cout << "呼号: " << callSign << std::endl;
        std::cout << "国家: " << country << std::endl;
        std::cout << "电台种类: " << station << std::endl;
        std::cout << "省份: " << provinceName << std::endl;
    } else {
        std::cout << "未找到呼号对应的信息" << std::endl;
    }
}

主程序

int main() {
    std::string callSign;
    std::cout << "请输入要查询的呼号: ";
    std::cin >> callSign;
    std::cout << "\n查询结果如下:\n" << std::endl;

    // 查询呼号信息
    queryCallSign(callSign);
    system("pause");
    return 0;
}

源代码

#include <iostream>
#include <map>
#include <string>

// 加载国家前缀规则
std::map<std::string, std::string> loadCountryPrefixRules() {
    std::map<std::string, std::string> countryPrefixRules;
    countryPrefixRules["B"] = "中国";
    return countryPrefixRules;
}

// 加载电台种类规则
std::map<char, std::string> loadStationTypeRules() {
    std::map<char, std::string> stationTypeRules;
    stationTypeRules['A'] = "个人业余电台(一级)";
    stationTypeRules['D'] = "个人业余电台(二级)";
    stationTypeRules['E'] = "个人业余电台(二级)";
    stationTypeRules['G'] = "个人业余电台(三级、四级、五级(收信台))";
    stationTypeRules['H'] = "个人业余电台(三级、四级、五级(收信台))";
    stationTypeRules['I'] = "个人业余电台(三级、四级、五级(收信台))";
    stationTypeRules['J'] = "业余信标台";
    stationTypeRules['L'] = "外籍及香港、澳门、台湾地区人员在中国内地设置的业余电台";
    stationTypeRules['R'] = "业余中继台";
    stationTypeRules['T'] = "特设业余电台";
    stationTypeRules['Y'] = "集体业余电台";
    return stationTypeRules;
}

// 加载大区和省份范围规则
std::map<char, std::map<std::string, std::pair<std::string, std::string> > > loadRegionProvinceRules() {
    std::map<char, std::map<std::string, std::pair<std::string, std::string> > > regionProvinceRules;

    // 第1区:北京
    regionProvinceRules['1'] = {
        {"北京", {"AA", "XZZ"}}
    };

    // 第2区:黑龙江、辽宁、吉林
    regionProvinceRules['2'] = {
        {"黑龙江", {"AA", "HZZ"}},
        {"吉林", {"IA", "PZZ"}},
        {"辽宁", {"QA", "XZZ"}}
    };

    // 第3区:河北、内蒙古、山西、天津
    regionProvinceRules['3'] = {
        {"天津", {"AA", "FZZ"}},
        {"内蒙古", {"GA", "LZZ"}},
        {"河北", {"MA", "RZZ"}},
        {"山西", {"SA", "XZZ"}}
    };

    // 第4区:山东、江苏、上海
    regionProvinceRules['4'] = {
        {"上海", {"AA", "HZZ"}},
        {"山东", {"IA", "PZZ"}},
        {"江苏", {"QA", "XZZ"}}
    };

    // 第5区:浙江、江西、福建
    regionProvinceRules['5'] = {
        {"浙江", {"AA", "HZZ"}},
        {"江西", {"IA", "PZZ"}},
        {"福建", {"QA", "XZZ"}}
    };

    // 第6区:河南、湖北、安徽
    regionProvinceRules['6'] = {
        {"安徽", {"AA", "HZZ"}},
        {"河南", {"IA", "PZZ"}},
        {"湖北", {"QA", "XZZ"}}
    };

    // 第7区:湖南、广东、广西、海南
    regionProvinceRules['7'] = {
        {"湖南", {"AA", "HZZ"}},
        {"广东", {"IA", "PZZ"}},
        {"广西", {"QA", "XZZ"}},
        {"海南", {"YA", "ZZZ"}}
    };

    // 第8区:四川、贵州、云南、重庆
    regionProvinceRules['8'] = {
        {"四川", {"AA", "FZZ"}},
        {"重庆", {"GA", "LZZ"}},
        {"贵州", {"MA", "RZZ"}},
        {"云南", {"SA", "XZZ"}}
    };

    // 第9区:陕西、甘肃、宁夏、青海
    regionProvinceRules['9'] = {
        {"陕西", {"AA", "FZZ"}},
        {"甘肃", {"GA", "LZZ"}},
        {"宁夏", {"MA", "RZZ"}},
        {"青海", {"SA", "XZZ"}}
    };

    // 第0区:新疆、西藏
    regionProvinceRules['0'] = {
        {"新疆", {"AA", "FZZ"}},
        {"西藏", {"GA", "LZZ"}}
    };

    return regionProvinceRules;
}

// 判断后缀是否在范围内
bool isWithinRange(const std::string &suffix, const std::string &rangeStart, const std::string &rangeEnd) {
    return suffix >= rangeStart && suffix <= rangeEnd;
}

// 查询呼号
void queryCallSign(const std::string &callSign) {
    // 加载各类规则
    auto countryRules = loadCountryPrefixRules();
    auto stationTypeRules = loadStationTypeRules();
    auto regionProvinceRules = loadRegionProvinceRules();

    // 确保呼号至少有5位
    if (callSign.length() < 5) {
        std::cout << "呼号格式不正确" << std::endl;
        return;
    }

    // 解析国家前缀
    std::string country = countryRules[callSign.substr(0, 1)];

    // 解析电台种类
    char stationType = callSign[1];
    std::string station = stationTypeRules[stationType];

    // 解析地区分区
    char region = callSign[2];

    // 解析后缀
    std::string suffix = callSign.substr(3, 2); // 假设后缀长度为2位

    // 查找该地区的省份范围
    std::string provinceName = "未知省份";
    if (regionProvinceRules.find(region) != regionProvinceRules.end()) {
        for (const auto &province: regionProvinceRules[region]) {
            if (isWithinRange(suffix, province.second.first, province.second.second)) {
                provinceName = province.first;
                break;
            }
        }
    }
    // 处理特殊情况(业余信标台、卫星业余电台、特设业余电台)
    if (stationType == 'J') {
        char suffix1 = callSign[3];
        if (suffix1 == 'H' || suffix1 == 'V' || suffix1 == 'U') {
            station = "HF、VHF、UHV频段信标台";
        } else if (suffix1 == 'D') {
            station = "业余无线电测向专用信标台";
        } else if (suffix1 == 'S' && region == '1') {
            station = "卫星业余电台";
        } else if (suffix1 == 'T') {
            station = "特设业余电台";
        }
    }
    // 输出结果
    if (!country.empty() && !station.empty() && provinceName != "未知省份") {
        std::cout << "呼号: " << callSign << std::endl;
        std::cout << "国家: " << country << std::endl;
        std::cout << "电台种类: " << station << std::endl;
        std::cout << "省份: " << provinceName << std::endl;
    } else {
        std::cout << "未找到呼号对应的信息" << std::endl;
    }
}

int main() {
    std::string callSign;
    std::cout << "请输入要查询的呼号: ";
    std::cin >> callSign;
    std::cout << "\n查询结果如下:\n" << std::endl;

    // 查询呼号信息
    queryCallSign(callSign);
    system("pause");
    return 0;
}

尾声

后续计划:

  • [ ] 支持全球呼号
  • [ ] 添加GUI

有更多想法?欢迎讨论👏

免费评分

参与人数 5吾爱币 +11 热心值 +3 收起 理由
苏紫方璇 + 7 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
boing + 1 我很赞同!
smilenet + 1 谢谢@Thanks!
luliucheng + 2 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
不负韶华 + 1 我很赞同!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

BrutusScipio 发表于 2024-11-25 14:52
如果不是有单文件需求的话不建议硬编码,可以写个配置文件文件运行时读取 现代的话就XML或者JSON 只是根据区位字符解析的话,GUI用imgui做个输入框输出框就可以
smilenet 发表于 2024-10-4 00:02
吾爱蛋蛋 发表于 2024-10-1 00:48
kim945 发表于 2024-10-1 01:19
这个厉害啊,明年考初级证,准备弄个小电台玩
单位领导说,中级证之后可以让我拿单位的练练
7845 发表于 2024-10-1 04:46
先插个眼待后面需要取
hunkguo 发表于 2024-10-1 08:24
简单明了,学习c++有用。
 楼主| bgwu666 发表于 2024-10-1 10:25
kim945 发表于 2024-10-1 01:19
这个厉害啊,明年考初级证,准备弄个小电台玩
单位领导说,中级证之后可以让我拿单位的练练

今年先把初级先考了吧,中级需要初级证持有一段时间才能再考
tp206555 发表于 2024-10-1 13:01
没有证 来学习一下
arthas19 发表于 2024-10-2 02:56

谢谢分享,代码靓丽;

现在如果是做GUI,是用QT么,还是用VS的?  

不如不忙着搞GUI,映射表如果不写在代码里面,写在外面,会不会更灵活一些
 楼主| bgwu666 发表于 2024-10-2 13:43
arthas19 发表于 2024-10-2 02:56
谢谢分享,代码靓丽;

现在如果是做GUI,是用QT么,还是用VS的?  

感谢发表意见,目前还没着手研究GUI,所以暂时无法确定使用何种GUI框架。至于映射表写在代码中是因为中国呼号命名规则几乎不会变动,写死是一种比较简单的方式。后续在添加全球呼号支持时,一定是会把映射表单独写到文件中,通过加载映射文件来解析呼号的。
unix2005 发表于 2024-10-3 17:05
感谢分享,现在能做c/c++的好像越来越少了!
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-12-15 09:05

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表