#c #visual-studio-2019
#c #visual-studio-2019
Вопрос:
Я практиковал различные способы отфильтровывания нежелательных символов мусора из объекта nlohmann:: json в std::string, и я только что закончил следующую функцию, которая дала мне довольно хороший результат (игнорируя, что я, конечно, пишу неаккуратный код для начинающих):
//This string is what I'm testing with as input.
std::string initial = "EA/1n n $9.34n n ";
std::string filter(std::string s) {
std::stringstream ss(s);
char c;
std::string final_string = "";
while (ss >> c) {
if (c == ' ') {
char temp_c = c;
while (ss >> c) {
if (c == ' ') {
continue;
}
else {
final_string = temp_c;
break;
}
}
}
else {
final_string = c;
}
}
return final_string;
}
//this is string that is produced when s is returned to main
result = "EA/1 $9.34"
Я не уверен, почему ‘ n’ и ‘ t’ также отфильтровываются, хотя я нацеливался только на ‘ ‘ на этом этапе тестирования. Я могу предоставить фотографию разбивки того, что именно показывает Visual Studio 2019, initial
если это необходимо. Любая информация была бы наиболее полезной, поскольку я буду работать над другими строками с аналогичными составами в течение следующих нескольких дней.
ОТРЕДАКТИРОВАНО: я изменил переменную, которая возвращается из функции, с s
на final_string
. Извините за путаницу.
ОТРЕДАКТИРОВАННОЕ2: Я выбрал ответ Реми Лебо, потому что это привело меня к пониманию того, что моя фильтрация действительно не работала вообще, что научило меня более тщательно отлаживать, прежде чем тратить ваше время. Результат, к которому я пришел, был именно тем, что я хотел, что заставило меня поверить, что мой код был каким-то образом более эффективным, отсюда и мое замешательство. Теперь я буду знать лучше, ха-ха. В любом случае, ответ Реми помог мне решить то, что мне было интересно, и дал мне хороший совет для продвижения вперед.
Комментарии:
1. Подсказка. Попробуйте использовать отладчик. Выполняется
(c == ' ')
ли условие хотя бы один раз?2.
ss >> std::noskipws
? Кроме того, вы возвращаете ту же строку, которую вам передали? Я не думаю, что это рассматривалось?3.
std::copy_if
делает то, что вы хотите.4. @S.M. не само по себе, это не так. Вам нужно было бы соединить его
std::back_inserter()
, например, с . Это также не будет обрабатывать случай, когда код OP использует внутренний цикл для минимизации прогонов из 2 пробелов в 1 пробел5. @sweenish Если бы OP просто хотел удалить все пробелы, удаление-стирание сделало бы это действительно тривиальным, но удаление-стирание не будет делать то, что запрашивает OP, а именно сокращение всех последовательных пробелов в один пробел.
Ответ №1:
В этом коде:
while (ss >> c) {
if (c == ' ') {
if
НИКОГДА не будет вычисляться как true
, потому operator>>
что по умолчанию пропускает начальные пробелы, которые включают пробелы, табуляции и разрывы строк. Так c
что никогда не будет такого пробельного символа , как ' '
.
Либо:
- используйте
std::noskipws
, как @WhozCraig , предложенный в комментариях:
while (ss >> std::noskipws >> c)
- используйте
std::istream::get()
, который не пропускает пробелы:
while (ss.get(c))
При этом в вашем коде есть другие ошибки.
Вы возвращаете неизмененное s
вместо подготовленного final_string
.
Похоже, что ваш внутренний while
цикл пытается свести к минимуму количество пробелов 2 в 1 пробел для вывода. Что нормально, за исключением того, что теряется символ, который завершает обнаруженный запуск.
Попробуйте что-то более похожее на это:
std::string filter(const std::string amp;s) {
std::istringstream iss(s);
char c;
std::string final_string;
while (iss.get(c)) {
if (c == ' ') {
while (iss.get(c)) {
if (c != ' ') {
final_string = ' ';
final_string = c;
break;
}
}
}
else {
final_string = c;
}
}
return final_string;
}
Наконец, при создании нового std::string
таким образом, как правило, более эффективно использовать std::ostringstream
вместо operator =
(если вы reserve()
std::string
не заранее), например:
std::string filter(const std::string amp;s) {
std::istringstream iss(s);
char c;
std::ostringstream final_string;
while (iss.get(c)) {
if (c == ' ') {
while (iss.get(c)) {
if (c != ' ') {
final_string << ' ' << c;
break;
}
}
}
else {
final_string << c;
}
}
return final_string.str();
}
Ответ №2:
Проблема заключается в std::stringstream::operator>>() функции. Я уверен, что ‘n’, ‘ t’ и пробел экранируются в функции. Следующий код выдаст тот же результат, который вы уже получили.
while (ss >> c) {
final_string = c;
}
return final_string
Будет лучше использовать базовый код, а не stringstream, как показано ниже.
std::string filter(std::string s) {
char c;
int i = 0;
std::string final_string = "";
do{
c = s[i];
if (c != ' ') {
final_string = c;
}
i ;
} while (c != 0);
return final_string;
}
Комментарии:
1. Сначала я подумал то же самое, пока не перечитал код OP и не понял, что он не удаляет ВСЕ символы пробела, а только (безуспешно пытаясь) минимизировать количество пробелов 2 в 1 пробел.
Ответ №3:
Предполагая, что целью является сжатие последовательных запусков табуляций и пробелов до одного пробела, но сохранение новых строк, я бы, вероятно, поступил немного по-другому.
#include <locale>
#include <iostream>
#include <algorithm>
#include <iterator>
#include <sstream>
#include <numeric>
class my_ctype : public std::ctype<char> {
mask my_table[table_size];
public:
my_ctype(size_t refs = 0) : std::ctype<char>(amp;my_table[0], false, refs){
std::copy_n(classic_table(), table_size, my_table);
my_table['n'] = mask();
}
};
int main() {
std::stringstream input("EA/1n n $9.34n n ");
std::locale ss(std::locale::classic(), new my_ctype);
input.imbue(ss);
std::string word;
while (input >> word)
std::cout << '"' << word << ""n";
}
Это основано на том факте, что поток уже использует языковой стандарт, чтобы выяснить, являются ли символы пробелами, и использует это, чтобы решить, что читать в строке. Итак, здесь мы воспользуемся этим и просто слегка изменим его, чтобы классифицировать новые строки как не являющиеся пробелами, чтобы они были сохранены в выходных данных. Кроме этого, поток уже делает в значительной степени то, что мы хотим, зная, как игнорировать последовательные прогоны пробелов, поэтому мы просто используем это вместо дублирования.