我正在读取一个每行有几个不同字段的大文件。通过类比,您可以将文件的每行视为代表一名员工,其中一个字段包含他们工作的部门名称。但是,部门名称可以由任意4-5个ASCII字符组成(例如:"1234", "ABCD", "P+0$i"
目前,我(天真地)将字符存储为std::string,但我注意到我已经执行了很多耗时的字符串比较。因此,我想从文件中读取字段,将字符串转换为数字(可能是无符号int?),然后再进行许多数值比较(并避免字符串比较)。当然,我需要一种方法将数字转换回字符串以供输出。
我的大多数在线搜索都显示"将字符串转换为数字",它讨论了使用stringstream将数字字符串转换为某种类型的int的使用。这不是特别有帮助,我似乎不能拿出一个适当的搜索查询找到一个解决方案。有人能告诉我相关的来源或提供一种方法来执行这种转换吗?
嗯,如果你有多达5个ASCII字符,那么最简单的方法是用你喜欢的字符填充到8,然后是*reinterpret_cast<uint64_t*>(the_id.data())
。
如果你想让字符表示适合32位int,你需要做更多的工作:简单地丢弃高阶位(可能是因为ASCII码是0-127)仍然留下7*5 = 35位-对于32位类型来说太多了。假设id不包含任何控制代码(即ASCII码0-31),您可以像这样实现base-96编码的打包:
unsigned base = 128 - 32;
// pad c out to 5 characters if necessary.
unsigned idnum = (((((c[0] - 32) * base + (c[1] - 32)) * base + (c[2] - 32)) * base + (c[3] - 32)) * base + (c[4] - 32)) * base + c[5] - 32;
你可能会发现使用循环更容易阅读:
unsigned idnum = 0;
for (size_t i = 0; i < 5; ++i)
{
idnum *= base;
idnum += c[i] - ' ';
}
使用% base
将数字解包回字符串值以获得最后一位数字,然后使用/ base
准备获得下一个....
- 创建一个具有部门名称->整数映射的映射。根据部门名称的固定程度,可以从配置文件中读取它们,也可以静态地定义映射。在需要时,创建反向映射以映射integer -> string。
- 在读取文件时,查找映射中的关联键并将其存储在数据结构中。
- 当需要时,在反向映射中查找部门名称
考虑到std::string相等操作对于任意长度的数据实际上是有效的,并且您需要保留实际的字符串值,我觉得您可能需要在其他地方寻找性能改进。查看您的需求,看起来您只需要为您的对象提供更好的搜索效率。std::unordered_map
容器可能是一个很好的备选方案。它是一个关联容器,通过键进行查找的时间是恒定的。您可以将数据的其他集合存储为unordered_map的值类型,并将关联键设置为您想要查找的键。下面是一些类型的示例,这些类型支持通过字符串查找数据的匹配子集。
struct Employee;
typedef std::vector<std::shared_ptr<Employee>> Employees;
typedef std::unordered_map<std::string, Employees> EmployeeByLookup;
然后您可以像这样查找匹配给定键值的所有员工。
static EmployeeByLookup byDepartment;
Employees& GetDepartmentList(const std::string& department)
{
return byDepartment[department];
}
如果您需要通过值而不是通过关联键查找对象,那么我建议您查看std::unordered_set
。它还具有查找时间为常数的平均复杂度。如果需要优化内部哈希性能,可以为对象创建自己的哈希函数。
我使用unordered_map
示例创建了一个简单的应用程序。如果你感兴趣的话可以看一下
c++ 11有std::stoi
。除此之外,还可以使用stringstream进行转换:
std::istringstream iss("1234");
int x;
if ( iss >> x )
std::cout << "Got " << x << "n";
else
std::cout << "String did not contain a numbern";
您可以从iss
中执行其他流提取,就像您习惯使用cin
一样。
我不知道为什么你认为stringstream建议"不是很有用"?