#c #string
#c #строка
Вопрос:
В настоящее время я реализовал эту логику для получения последней строки из строки. Я уверен, что это неэффективное решение.
...
string response;
while (1) {
string newResponse = SocketRead();
response = newResponse;
if(checkIfReceiveComplete(response)) {
break;
}
}
...
bool checkIfReceiveComplete(string amp;response) {
size_t index = response.find_last_of("rn");
if (response 1 == response.length()) {
response.pop_back();
response.pop_back();
index = response.find_last_of("rn");
}
string lastLine = response.substr(index 1);
return (lastLine.find(" OK ") != string::npos);
}
Пожалуйста, дайте мне знать, насколько эффективно это может быть реализовано.
Примечание: я не читаю из файла. Поэтому я не уверен, можно ли использовать seekg().
Комментарии:
1.
abort()
даст те же результаты, что и ваш алгоритм для некоторых входных данных (например, тех, которые вообще не содержат новых строк). Достаточно ли это эффективно?2. Если серьезно, было бы немного эффективнее разбить входной поток на строки в источнике. Просканируйте каждый прочитанный буфер на
rn
, создайте вектор строк. Проще простого.3. @niklaz Я не выполняю операцию чтения файла. Как можно будет использовать seekg() для перехода к последней строке в строке из миллиона строк или million (n)?
4. @RamKishore Ты действительно читаешь 1 миллион строк в
string
? В это трудно поверить, если длина каждой строки составляет всего 20 символов, то ваша строка будет занимать 20 МБ … Я чувствую, что было бы трудно иметь строку такого размера в программе.5. Итак, на шаге, на котором вы читаете строку из сокета, ее длина должна быть равна размеру буфера, если только мы не получили последнюю строку правильно? Так что, если это так, то нет необходимости искать каждый раз, только если вы получаете строку, меньшую размер буфера. Также, если ее размер такой же, а последний символ — «r n»‘, тогда вам также нужно выполнить поиск, просто добавьте
Ответ №1:
std::string
хранит char*
внутри, которое является последовательным в пространстве, таким образом, к нему легко получить доступ. Мы можем использовать это для поиска с обратной стороны последнего (или предпоследнего) возвращаемого символа:
inline bool is_return(const charamp; input)
{
return input == 'n' || input == 'r';
}
string last_line (const stringamp; input)
{
if(input.length() == 1) return input;
size_t position = input.length()-2; // last character might be a return character, we can jump over it anyway
while((not is_return(input[position])) and position > 0) position--;
// now we are at the n just before the last line, or at the first character of the string
if(is_return(input[position])) position = 1;
// now we are at the beginning of the last line
return input.substr(position);
}
Этот код предполагает, что входные данные действительно большие, в то время как выходные данные (/ size последней строки) — нет. Не использует никаких специальных функций STL, возможно, там есть несколько приятных трюков, но они должны сработать.
Одним из улучшений может быть доступ к некоторому блоку впереди, когда позиция уменьшается, чтобы предварительно загрузить несколько блоков данных в кэш. Не уверен, как это делается в идеале, если это оказывает сильное влияние или даже необходимо, возможно, кто-то другой может уточнить. Не обязательно, если выполняется предположение о том, что последняя строка маленькая.
Комментарии:
1. Спасибо за ответ. Будет ли это эффективнее, чем функция find_last_of(), которую я использовал?
2. @RamKishore Эффективность этого заключается в O (M), где M — длина последней строки, а не длина всей строки. Лучшего времени быть не должно, если у вас нет какого-либо способа предсказать эту длину. Сравнение с
find_last_of
несколько затруднено, см. cplusplus.com/reference/string/string/find_last_of , «Сложность: не указана, но обычно до линейной по длине строки (или pos), умноженной на количество символов для сопоставления (в худшем случае)». Я бы предположил, чтоfind_last_of
выполняется поиск строки с самого начала, таким образом, требуется O (N) для N, являющегося длиной строки.3. @RamKishore В любом случае, у вас уже есть код для обоих методов, почему бы вам просто не попробовать это на каком-нибудь вашем реалистичном примере? Может быть, с помощью
std::chrono::high_resolution_clock
точного измерения времени?4. Спасибо за информацию. Понял разницу. Я думал, что find_last_of начнется с обратного. Спасибо за разъяснение.
5. @RamKishore Я не знаю, работает ли это, может быть. Не знаю деталей ее реализации. Снова попробуйте и сравните. Если это произойдет, на самом деле нет возможности для улучшения.