前言
自从接触业余无线电后,就会对见到的每个呼号都产生好奇心,总想查一查这些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;
}
尾声
后续计划:
有更多想法?欢迎讨论👏