user2919996
user2919996

Reputation:

How to find a single word in "std::vector<char>" container

I have a mixed binary (i.e. image) and some human readable data (i.e. HTTP header) stored in the "std::vector<char>" container. (Data is separated by "CRLFCRLF (\r\n\r\n)" indicator)

Can anyone suggest a way on how to find a start position of "\r\n\r\n" in the "std::vector<char>" container?

Is it possible to do something like "std::size_t pos = data.find("\r\n\r\n"); (where data is a "std::vector<char>")" using STL library?

Thanks.

Upvotes: 6

Views: 6648

Answers (3)

YenForYang
YenForYang

Reputation: 3304

// As mentioned, you can use a basic C-style string.
// But, for convenience, an array works just as well
// Using an array allows for us to use std::begin() and std::end()
static constexpr const char DOUBLE_CLRF[]{'\r','\n','\r','\n'};

/**
 <summary>        Finds the first occurrence of "\r\n\r\n".   </summary>
 <param name="v"> Contains the char data you want to process. </param>
 <returns>        The position of the first "\r\n\r\n".       </returns>
 */
ptrdiff_t findFirstDoubleClrf(const std::vector<char>& v) {
    const auto it = std::search(v.begin(), v.end(), std::begin(DOUBLE_CLRF), std::end(DOUBLE_CLRF));
    return std::distance(v.begin(), it);
}

/**
 <summary>        Finds the last occurrence of "\r\n\r\n".    </summary>
 <param name="v"> Contains the char data you want to process. </param>
 <returns>        The position of the last "\r\n\r\n".        </returns>
 */
ptrdiff_t findLastDoubleClrf(const std::vector<char>& v) {
    const auto it = std::find_end(v.begin(), v.end(), std::begin(DOUBLE_CLRF), std::end(DOUBLE_CLRF));
    return std::distance(v.begin(), it);
}

Now suppose your binary data with human readable text is in your (as mentioned) std::vector<char> named data.

// To get the *first* match
auto pos = findFirstDoubleClrf(data);

// To get the *last* match
auto lastPos = findLastDoubleClrf(data);

// Note: std::distance returns a signed value rather than unsigned (e.g. size_t)
// You can, of course, static_cast<size_t>(pos) if desired.

But if you miss the find() method std::string offers, and you have C++17 available, std::string_view can be worked in without copying the entire std::vector<char> to offer similar functionality.

std::string_view sv(&data[0], data.size());
auto pos = sv.find("\r\n\r\n");
auto lastPos = sv.rfind("\r\n\r\n");

Upvotes: 1

Marshall Clow
Marshall Clow

Reputation: 16690

You don't need to put the pattern you're looking for into a container. A C string is enough.

std::vector<char> v = ....;
const char *crlf2 = "\r\n\r\n";
auto it = std::search(v.begin(), v.end(), crlf2, crlf2 + strlen(crlf2));

Anyway, after this, it will contain an iterator into the vector v where that pattern begins (or v.end() if the pattern is not found).

You can convert that into an index with std::distance(v.begin(), it) or just it - v.begin()

Upvotes: 9

juanchopanza
juanchopanza

Reputation: 227538

You can use std::search to search for the first occurrence of the character sequence of interest. You would have to place that sequence in an array or container.

std::vector<char> v = ....;
std::vector<char> start{'\r', '\n', '\r', '\n'};
auto it = std::search(v.begin(), v.end(), start.begin(), start.end());

Upvotes: 5

Related Questions