C++ 无序映射中有效的字符串到键匹配?
将这些字符串映射到函数的最有效方法是哈希表:C++ 无序映射中有效的字符串到键匹配?,c++,regex,c++11,string-matching,unordered-map,C++,Regex,C++11,String Matching,Unordered Map,将这些字符串映射到函数的最有效方法是哈希表: std::string a="/foo/", b="/foo/car/", c="/foo/car/can/", d="/foo/car/haz/"; 不幸的是,当您想要匹配最简单的模式时,事情会变得更加复杂: /foo/[a-Z|0-9]+>/ /foo/[a-Z|0-9]+>/bar/[a-Z|0-9]+/ 有人告诉我,库对我的需求来说太过苛刻了;而且它的开销是相当大的 在这里使用哈希表(std::unordered_map)可能
std::string a="/foo/", b="/foo/car/", c="/foo/car/can/", d="/foo/car/haz/";
不幸的是,当您想要匹配最简单的模式时,事情会变得更加复杂:
/foo/[a-Z|0-9]+>/
/foo/[a-Z|0-9]+>/bar/[a-Z|0-9]+/
有人告诉我,
库对我的需求来说太过苛刻了;而且它的开销是相当大的
在这里使用哈希表(std::unordered_map
)可能是一个有效的选择;在开关/案例中的单个解析中检查[a-Z | 0-9]+
。参数的数量(在/
上拆分)并使用/
的数量,然后使用任意数量的参数来决定采用哪条路径:
"/foo/" => {<function>, "/foo/can/", "/foo/[a-Z|0-9]+/bar/"}
"/foo/xflkjkjc34v" => {<function>, "/foo/can/", "/foo/[a-Z|0-9]+/bar/"}
"/foo/can" => {<function>, "/foo/can/", "/foo/[a-Z|0-9]+/bar/"}
"/foo/vxcvxc86vzxc/bar/" => {<function>, "/foo/[a-Z|0-9]+/bar/haz"}
“/foo/”=>{,“/foo/can/”,“/foo/[a-Z | 0-9]+/bar/”}
“/foo/xflkjkjc34v”=>{,“/foo/can/”,“/foo/[a-Z | 0-9]+/bar/”}
“/foo/can”=>{,/foo/can/”,“/foo/[a-Z|0-9]+/bar/”}
“/foo/vxcvxc86vzxc/bar/”=>{,“/foo/[a-Z|0-9]+/bar/haz”}
有可能实施;但是这是最好的方法吗?理想的数据结构应该是一个trie,其中每个斜线分隔的段与
无序映射中的最后一个无通配符字符串匹配,甚至是排序的向量(可以分别在O(1)或O(logN)中进行匹配),然后,如果没有找到匹配的正则表达式向量(您可能需要逐个尝试-O(N))。根据您的性能需求,您可以通过将常量字符串视为正则表达式并始终在trie中的每个节点上执行O(N)搜索来简化操作
+----------+ +---------------+ +-----------+
| fixed: | | fixed: | | fixed: |
| foo -+---->| bar -|---> fn_foo_bar --| xxx -|---> fn_foo_X_xxx
| abc -+- | | / | |
| regexp: | \ | regexp: | / | regexp: |
+----------+ | | [A-Z0-9]+ -|--------------- +-----------+
| +---------------+
|
\->+---------------+
| fixed: |
...
如果您对fixed和reg-exp组件的潜在变化数量有更具体的了解,您可能能够进一步优化,但这是一个具有合理可扩展性的通用解决方案。关于我的评论,以下是我认为对您的问题既简单又合理有效的解决方案。这是一个伪代码,因为我不知道问题的具体情况(例如,映射什么类型的函数等)
#定义最大分段255
#定义标签长度10
#定义键长度(最大线段*标签长度)
#定义标签格式“%10u”
// ------------------------------------------------------------------------
/**
*由字符串中的位置和长度定义的简单段。
*/
结构段
{
未签名pos;
无符号len;
};
/**
*regexp的容器示例。
*如果在regexp中有嵌套结构,则这可能是一棵树。
*MyRegexp是一个定义匹配的对象(常量字符*段,无符号len)
*/
std::vector regexps;
/**
*映射函数位于由内置键索引的无序_映射中
*解析下面的_段。
*/
std::无序地图映射的乐趣;
// ------------------------------------------------------------------------
无效拆分地址(常量std::字符串和地址,std::向量和段)
{
//将地址拆分为以“/”分隔的段
}
void parse_段(const std::string&address,const std::vector&segments,char*key)
{
//键的长度应为MAX_SEGMENTS*LABEL_length。
//循环每个段的所有正则表达式。
//如果某些正则表达式与其他正则表达式的子集匹配,则
//在regexp中有一个树结构,您可以
//利用此结构可以更快地匹配细分市场。
//下面是一个创建密钥的伪代码示例,假设
//你有一个正则表达式的向量。
静态字符buf[标签长度+1];
for(无符号i=0;i
您是否只有两个箱子(带和不带吧台)?你需要它的效率有多高?拆分方法有什么问题?如果它实际上看起来像第二个代码块中的示例,则只需计算/
的数量。如果映射的函数不依赖于映射它的键(这意味着只有两个函数,每个函数对应一个大小写),那么您甚至不需要哈希表;这些只是例子。实际上会有更多的组合;RHS支持数以万计的图案。编辑:我将对示例进行更具体的修改。您是否打算编写一个包含成千上万个案例的转换?我有一个单独的解析实现,用于输出/
上划分的[a-Z]+[0-9]*
范围内的段;并且在[0-9]+
范围内。谢谢你;我曾经考虑过尝试一下。是否有一个很好的实现来完成大部分设置例如:甚至。
#define MAX_SEGMENTS 255
#define LABEL_LENGTH 10
#define KEY_LENGTH (MAX_SEGMENTS*LABEL_LENGTH)
#define LABEL_FORMAT "%10u"
// ------------------------------------------------------------------------
/**
* Simple segment defined by position and length in a string.
*/
struct Segment
{
unsigned pos;
unsigned len;
};
/**
* Example of container for regexps.
* This could be a tree if you had a nested structure among your regexps.
* MyRegexp is an object that defines match( const char* segment, unsigned len )
*/
std::vector<MyRegexp> regexps;
/**
* Mapped functions are in an unordered_map indexed by keys typically built in
* parse_segments below.
*/
std::unordered_map<std::string,Function*> mapped_fun;
// ------------------------------------------------------------------------
void split_address( const std::string& address, std::vector<Segment>& segments )
{
// Split address into segments separated by '/'
}
void parse_segments( const std::string& address, const std::vector<Segment>& segments, char *key )
{
// key should be of length MAX_SEGMENTS*LABEL_LENGTH.
// Loop over all regular expressions for each segment.
// If some regular expressions match a subset of others, then
// you have a tree structure among your regexps and you can
// exploit this structure to match your segments faster.
// Here is an example of pseudo-code to create your key, assuming
// that you have a vector of regexps.
static char buf[ LABEL_LENGTH+1 ];
for ( unsigned i = 0; i < regexps.size(); ++i )
if ( regexps[i].match( &address[segments[i].pos], segments[i].len ) )
{
sprintf( buf, LABEL_FORMAT, i );
memcpy( key+LABEL_LENGTH*i, buf, LABEL_LENGTH );
}
}
Function* map_address( const std::string& address )
{
// Split address into segments
std::vector<Segment> segments;
split_address( address, segments );
// Match segments to regexps
static std::string key; key.resize(KEY_LENGTH);
parse_segments( address, segments, &key[0] );
// Map address to function
return mapped_fun.find(key) == mapped_fun.end() ?
nullptr : mapped_fun[key];
}