Сравнение элементов текстового файла - PullRequest
0 голосов
/ 20 января 2020

Я пытаюсь сравнить блоки из четырех чисел друг с другом, чтобы создать новый выходной файл только с теми, которые соответствуют этому: четыре числа git, у которых все цифры одинаковы.

Это мой код для входного файла:

int main() { ofstream outfile ("text.txt"); outfile << "1111 1212 4444 \n 2222 \n \n 8888 4567" <<endl;

Я хочу разбить его на блоки по четыре, например, "1111", "1212" и т. Д. чтобы иметь возможность писать только те, которые соответствуют требованию в новом выходном файле. Я решил преобразовать весь файл в целочисленный вектор, чтобы иметь возможность сравнивать их.

   char digit;
   ifstream file("text.txt");
   vector <int> digits;

   while(file>>digit)
   {
      digits.push_back(digit - '0');
   }

и я полагаю, что метод, который их сравнивает, будет выглядеть примерно так:

bool IsValid(vector<int> digits){

   for (int i=0; i<digits.size() i++)
   {
      if(digits[0] == digits[1] == digits[2] == digits [3])
         return true; 

      else 
      {
         return false;
      }
   }
}

Однако это будет просто сравнить первый блок, вы бы сделали это по-другому? или я должен продолжать делать векторную идею.

Ответы [ 4 ]

1 голос
/ 23 января 2020

Хм, все, что я видел, довольно сложно.

Очевидно, вы хотите проверить шаблон в строке. И шаблоны обычно сопоставляются с регулярными выражениями.

Это даст вам чрезвычайно короткое решение. Используйте std::regex. Регулярные выражения являются частью стандартной библиотеки C ++. И они также просты в использовании. И для вашего случая вы регулярное выражение (\d)\1{3}. Таким образом, ди git, за которым следуют 3 одинаковые цифры.

Затем программа сводится к одному утверждению:

#include <sstream>
#include <iostream>
#include <iterator>
#include <algorithm>
#include <string>
#include <regex>

std::istringstream testData{R"(1111 1212 444414 555
2222

8888 4567)"};

int main()
{
    std::copy_if(
        std::istream_iterator<std::string>(testData), 
        {},
        std::ostream_iterator<std::string>(std::cout,"\n"),
        [](const std::string& s){
            return std::regex_match(s,std::regex(R"((\d)\1{3})"));
        }
    );

    return 0;
}

Конечно, вы можете использовать любой std::fstream вместо std::istringstream

И, конечно, это только одно из многих возможных и, возможно, не лучшее решение. , .

0 голосов
/ 25 января 2020

Другой подход состоит в том, чтобы просто обрабатывать каждый ввод как строку, и l oop над каждым символом в строке, подтверждая, что он является di git и равен предыдущему символу. Если он не проходит ни одного теста, то прочитанное не является целым числом со всеми равными цифрами.

Например, вы можете сделать:

#include <iostream>
#include <sstream>
#include <string>
#include <cctype>

int main (void) {

int main (void) {

    std::string s;
    std::stringstream ss { "1 11 1111 foo 2222\nbar 1212\n4444\n8888\n4567\n"
                            "3433333 a8\n9999999999999999999\n" };

    while (ss >> s) {                               /* read each string */
        bool equaldigits = true;                    /* flags equal digits */
        for (size_t i = 1; i < s.length(); i++)     /* loop 1 - length */
            /* validate previous & current digits & equal */
            if (!isdigit(s[i-1]) || !isdigit(s[i]) || s[i-1] != s[i]) {
                equaldigits = false;                /* if not set flag false */
                break;                              /* break loop */
            }
        /* handle empty-string or single char case */
        if (!s.length() || (s.length() == 1 && !isdigit(s[0])))
            equaldigits = false;
        if (equaldigits)                            /* if all digits & equal */
            std::cout << s << '\n';                 /* output string */
    }
}

Приведенный выше std::stringstream просто обеспечивает симулированный ввод для программы.

( примечание: вы можете l oop с std::string::iterator, если хотите, или использовать диапазоны for l oop и prev char для хранения последнего увиденного. Здесь также легко выполнить итерации по индексам)

Использование std :: string find_first_not_of

Использование существующих строковых функций обеспечивает другой способ. После сравнения того, что первый символ является ди git, вы можете использовать std :: basic_string :: find_first_not_of , чтобы просканировать остальную часть строки на наличие символа, который не совпадает с первым - если результат не равен std::string::npos, то ваша строка не совпадает с di git.

#include <iostream>
#include <sstream>
#include <string>
#include <cctype>

int main (void) {

    std::string s;
    std::stringstream ss { "1 11 1111 foo 2222\nbar 1212\n4444\n8888\n4567\n"
                            "3433333 a8\n9999999999999999999\n" };

    while (ss >> s) {                               /* read each string */
        if (!isdigit(s.at(0)))                      /* 1st char digit? */
            continue;
        /* if remainder of chars not equal 1st char - not equal digits */
        if (s.find_first_not_of(s.at(0)) != std::string::npos)
            continue;
        std::cout << s << '\n';
    }
}

Оба подхода дают один и тот же вывод.

Пример Использование / Вывод

$ ./bin/intdigitssame
1
11
1111
2222
4444
8888
9999999999999999999

Есть много других способов сделать это, как показывают другие хорошие ответы. Стоит понимать каждый подход.

0 голосов
/ 20 января 2020

Я решил преобразовать весь файл в целочисленный вектор, чтобы можно было их сравнить.

Затем вы можете извлечь int s из потока напрямую (file >> int_variable) и проверьте, кратны ли они 1111 или нет.

Предложения в коде:

#include <fstream>
#include <iomanip>
#include <iostream>
#include <vector>

bool IsValid(int number) {
    // Check that number is in the valid range and that it's a multiple of 1111.
    return number >= 0 && number <= 9999 && (number / 1111) * 1111 == number;
}

// A function to process the values in a stream
std::vector<int> process_stream(std::istream& is) {
    std::vector<int> digits;
    int number;

    while(is >> number) {
        if(IsValid(number)) // Only save valid numbers
            digits.push_back(number);
    }
    return digits;
}

int main() {
    std::vector<int> digits;

    // Check that opening the file succeeds before using it
    if(std::ifstream file = std::ifstream("text.txt")) {
        digits = process_stream(file);
    }

    // Print the collected int:s
    for(int x : digits) {
        std::cout << std::setw(4) << std::setfill('0') << x << '\n';
    }
}
0 голосов
/ 20 января 2020

Вы можете получить числа, затем легко их обработать следующим образом

#include<string>
#include<vector>
#include<fstream>
#include<iostream>
#include<cctype>

bool isValid(const std::string& str){

        return str.size() == 4 && isdigit(str[0]) && str.find_first_not_of(str[0]) ==std::string::npos;
    }

int main(){

    std::fstream inf;
    inf.open("text.txt");
    std::string tempStr{};
    std::vector<int> stringsVec;

    while(inf >> tempStr)
        if(isValid(tempStr)) stringsVec.push_back(std::stoi(tempStr));

    inf.close();

    //Displying them
    for(auto const & el : stringsVec)
        std::cout<<"\n"<<el; 


}

Вектор сохранит только действительные цифры (четыре цифры и имеет только одно значение) как целые числа

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...