Commit 75da0bec authored by zhujiashun's avatar zhujiashun

support_kv_pair_splitter: add basic features

parent 1ebba7f7
......@@ -407,19 +407,6 @@ void URI::SetH2Path(const char* h2_path) {
}
}
void QuerySplitter::split() {
butil::StringPiece query_pair(_sp.field(), _sp.length());
const size_t pos = query_pair.find('=');
if (pos == butil::StringPiece::npos) {
_key = query_pair;
_value.clear();
} else {
_key= query_pair.substr(0, pos);
_value = query_pair.substr(pos + 1);
}
_is_split = true;
}
QueryRemover::QueryRemover(const std::string* str)
: _query(str)
, _qs(str->data(), str->data() + str->size())
......
......@@ -195,68 +195,19 @@ inline std::ostream& operator<<(std::ostream& os, const URI& uri) {
}
// Split query in the format of "key1=value1&key2&key3=value3"
// This class can also handle some exceptional cases, such as
// consecutive ampersand, only equal sign, only key and so on.
class QuerySplitter {
class QuerySplitter : public butil::KeyValuePairsSplitter {
public:
QuerySplitter(const char* str_begin, const char* str_end)
: _sp(str_begin, str_end, '&')
, _is_split(false) {
}
QuerySplitter(const char* str_begin)
: _sp(str_begin, '&')
, _is_split(false) {
}
inline QuerySplitter(const char* str_begin, const char* str_end)
: KeyValuePairsSplitter(str_begin, str_end, '=', '&')
{}
QuerySplitter(const butil::StringPiece &sp)
: _sp(sp.begin(), sp.end(), '&')
, _is_split(false) {
}
inline QuerySplitter(const char* str_begin)
: KeyValuePairsSplitter(str_begin, '=', '&')
{}
const butil::StringPiece& key() {
if (!_is_split) {
split();
}
return _key;
}
const butil::StringPiece& value() {
if (!_is_split) {
split();
}
return _value;
}
// Get the current value of key and value
// in the format of "key=value"
butil::StringPiece key_and_value(){
return butil::StringPiece(_sp.field(), _sp.length());
}
// Move splitter forward.
QuerySplitter& operator++() {
++_sp;
_is_split = false;
return *this;
}
QuerySplitter operator++(int) {
QuerySplitter tmp = *this;
operator++();
return tmp;
}
operator const void*() const { return _sp; }
private:
void split();
private:
butil::StringSplitter _sp;
butil::StringPiece _key;
butil::StringPiece _value;
bool _is_split;
inline QuerySplitter(const butil::StringPiece &sp)
: KeyValuePairsSplitter(sp, '=', '&')
{}
};
// A class to remove some specific keys in a query string,
......
......@@ -22,6 +22,7 @@
#include <stdlib.h>
#include <stdint.h>
#include "butil/strings/string_piece.h"
// It's common to encode data into strings separated by special characters
// and decode them back, but functions such as `split_string' has to modify
......@@ -159,6 +160,82 @@ private:
const EmptyFieldAction _empty_field_action;
};
// Split query in the format according to the given delimiters.
// This class can also handle some exceptional cases, such as
// consecutive ampersand, only equal sign, only key and so on.
class KeyValuePairsSplitter {
public:
inline KeyValuePairsSplitter(const char* str_begin,
const char* str_end,
char key_value_delimiter,
char key_value_pair_delimiter)
: _sp(str_begin, str_end, key_value_pair_delimiter)
, _is_split(false)
, _key_value_delimiter(key_value_delimiter) {
}
inline KeyValuePairsSplitter(const char* str_begin,
char key_value_delimiter,
char key_value_pair_delimiter)
: _sp(str_begin, key_value_pair_delimiter)
, _is_split(false)
, _key_value_delimiter(key_value_delimiter) {
}
inline KeyValuePairsSplitter(const StringPiece &sp,
char key_value_delimiter,
char key_value_pair_delimiter)
: _sp(sp.begin(), sp.end(), key_value_pair_delimiter)
, _is_split(false)
, _key_value_delimiter(key_value_delimiter) {
}
inline const StringPiece& key() {
if (!_is_split) {
split();
}
return _key;
}
inline const StringPiece& value() {
if (!_is_split) {
split();
}
return _value;
}
// Get the current value of key and value
// in the format of "key=value"
inline StringPiece key_and_value(){
return StringPiece(_sp.field(), _sp.length());
}
// Move splitter forward.
inline KeyValuePairsSplitter& operator++() {
++_sp;
_is_split = false;
return *this;
}
inline KeyValuePairsSplitter operator++(int) {
KeyValuePairsSplitter tmp = *this;
operator++();
return tmp;
}
inline operator const void*() const { return _sp; }
private:
inline void split();
private:
StringSplitter _sp;
StringPiece _key;
StringPiece _value;
bool _is_split;
const char _key_value_delimiter;
};
} // namespace butil
#include "butil/string_splitter_inl.h"
......
......@@ -309,6 +309,19 @@ int StringMultiSplitter::to_double(double* pv) const {
return (endptr == field() + length()) ? 0 : -1;
}
void KeyValuePairsSplitter::split() {
StringPiece query_pair(_sp.field(), _sp.length());
const size_t pos = query_pair.find('=');
if (pos == StringPiece::npos) {
_key = query_pair;
_value.clear();
} else {
_key= query_pair.substr(0, pos);
_value = query_pair.substr(pos + 1);
}
_is_split = true;
}
} // namespace butil
#endif // BUTIL_STRING_SPLITTER_INL_H
......@@ -321,4 +321,56 @@ TEST_F(StringSplitterTest, split_limit_len) {
ASSERT_FALSE(ss2);
}
TEST_F(StringSplitterTest, key_value_pairs_splitter_sanity) {
std::string kvstr = "key1=value1&key2=value2&key3=value3";
{
butil::KeyValuePairsSplitter splitter(kvstr, '=', '&');
ASSERT_TRUE(splitter);
ASSERT_EQ(splitter.key(), "key1");
ASSERT_EQ(splitter.value(), "value1");
++splitter;
ASSERT_TRUE(splitter);
ASSERT_EQ(splitter.key(), "key2");
ASSERT_EQ(splitter.value(), "value2");
++splitter;
ASSERT_TRUE(splitter);
ASSERT_EQ(splitter.key(), "key3");
ASSERT_EQ(splitter.value(), "value3");
++splitter;
ASSERT_FALSE(splitter);
}
{
butil::KeyValuePairsSplitter splitter(kvstr.data(), kvstr.data() + kvstr.size(), '=', '&');
ASSERT_TRUE(splitter);
ASSERT_EQ(splitter.key(), "key1");
ASSERT_EQ(splitter.value(), "value1");
++splitter;
ASSERT_TRUE(splitter);
ASSERT_EQ(splitter.key(), "key2");
ASSERT_EQ(splitter.value(), "value2");
++splitter;
ASSERT_TRUE(splitter);
ASSERT_EQ(splitter.key(), "key3");
ASSERT_EQ(splitter.value(), "value3");
++splitter;
ASSERT_FALSE(splitter);
}
{
butil::KeyValuePairsSplitter splitter(kvstr.c_str(), '=', '&');
ASSERT_TRUE(splitter);
ASSERT_EQ(splitter.key(), "key1");
ASSERT_EQ(splitter.value(), "value1");
++splitter;
ASSERT_TRUE(splitter);
ASSERT_EQ(splitter.key(), "key2");
ASSERT_EQ(splitter.value(), "value2");
++splitter;
ASSERT_TRUE(splitter);
ASSERT_EQ(splitter.key(), "key3");
ASSERT_EQ(splitter.value(), "value3");
++splitter;
ASSERT_FALSE(splitter);
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment