Чтение целых чисел из текстового файла со словами - PullRequest
2 голосов
/ 18 января 2010

Я пытаюсь прочитать только целые числа из текстового файла, структурированного так ...

ALS 46000
BZK 39850
CAR 38000
//....

с использованием ifstream.

Я рассмотрел 2 варианта.

1) регулярное выражение с использованием Boost

2) Создание одноразовой строки (то есть я читаю одним словом, ничего с ним не делаю, затем читаю в партитуре). Однако это последнее средство.

Есть ли способы выражения в C ++, которые я хочу, чтобы ifstream читал только в тексте, который является целым числом? Я не хочу использовать регулярные выражения, если выясняется, что для этого есть гораздо более простой способ.

Ответы [ 6 ]

9 голосов
/ 18 января 2010

зачем делать простые вещи сложными?

что не так в этом:

ifstream ss("C:\\test.txt");

int score;
string name;
while( ss >> name >> score )
{
    // do something with score
}
4 голосов
/ 18 января 2010

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

+(omit[+(alpha|blank)] >> int_)

и одна строка кода (кроме определений переменных):

void extract_file()
{
    std::ifstream f("E:/dd/dd.trunk/sandbox/text.txt");    
    boost::spirit::istream_iterator it_begin(f), it_end;

    // extract all numbers into a vector
    std::vector<int> vi;
    parse(it_begin, it_end, +(omit[+(alpha|blank)] >> int_), vi);

    // print them to verify
    std::copy(vi.begin(), vi.end(), 
        std::ostream_iterator<int>(std::cout, ", " ));

}

вы получаете все числа в векторе сразу одной строкой, проще не бывает.


если вы не возражаете против использования boost.spirit2 . парсер для получения чисел только из строки

omit[+(alpha|blank)] >> int_

чтобы извлечь все

+(alpha|blank) >> int_

См. Всю программу ниже (Тест с VC10 Beta 2):

#include <boost/spirit/include/qi.hpp>  
#include <iostream>  
#include <string>  
#include <cstring> 
#include <vector>  

#include <fstream>
#include <algorithm>
#include <iterator>

using std::cout; 

using namespace boost::spirit;  
using namespace boost::spirit::qi;    

void extract_everything(std::string& line) 
{
    std::string::iterator it_begin = line.begin();
    std::string::iterator it_end   = line.end();    

    std::string s;
    int i;

    parse(it_begin, it_end, +(alpha|blank)>>int_, s, i);

    cout << "string " << s  
         << "followed by nubmer " << i 
         << std::endl;

}

void extract_number(std::string& line) 
{
    std::string::iterator it_begin = line.begin();
    std::string::iterator it_end   = line.end();    

    int i;

    parse(it_begin, it_end, omit[+(alpha|blank)] >> int_, i);

    cout << "number only: " << i << std::endl;

} 

void extract_line()
{
    std::ifstream f("E:/dd/dd.trunk/sandbox/text.txt");
    std::string s;
    int i; 

    // iterated file line by line
    while(getline(f, s))
    {
        cout << "parsing " << s << " yields:\n";
        extract_number(s);  // 
        extract_everything(s);
    }

}

void extract_file()
{
    std::ifstream f("E:/dd/dd.trunk/sandbox/text.txt");    
    boost::spirit::istream_iterator it_begin(f), it_end;

    // extract all numbers into a vector
    std::vector<int> vi;
    parse(it_begin, it_end, +(omit[+(alpha|blank)] >> int_), vi);

    // print them to verify
    std::copy(vi.begin(), vi.end(), 
        std::ostream_iterator<int>(std::cout, ", " ));

}

int main(int argc, char * argv[])  
{    
    extract_line();
    extract_file();

    return 0;  
}
* 1 028 * выходы:
parsing ALS 46000 yields:
number only: 46000
string ALS followed by nubmer 46000
parsing BZK 39850 yields:
number only: 39850
string BZK followed by nubmer 39850
parsing CAR 38000 yields:
number only: 38000
string CAR followed by nubmer 38000
46000, 39850, 38000,
1 голос
/ 18 января 2010

Вы можете позвонить игнорировать , чтобы пропустить указанное количество символов.

istr.ignore(4);

Вы также можете сказать, чтобы он останавливался на разделителе. Вам все равно нужно знать максимальное количество символов, которое может быть ведущей строкой, но это также будет работать для более коротких ведущих строк:

istr.ignore(10, ' ');

Вы также можете написать цикл, который будет просто читать символы до тех пор, пока вы не увидите первый символ:

char c;
while (istr.getchar(c) && !isdigit(c))
{
    // do nothing
}
if (istr && isdigit(c))
    istr.putback(c);
0 голосов
/ 18 января 2010

Вы можете создать фасет ctype, который классифицирует буквы как пробелы. Создайте локаль, которая использует этот фасет, а затем наполните поток этой локалью. Имея это, вы можете извлекать числа из потока, но все буквы будут обрабатываться как пробел (то есть, когда вы извлекаете числа, буквы будут игнорироваться, как пробел или табуляция):

Такая локаль может выглядеть так:

#include <iostream>
#include <locale>
#include <vector>
#include <algorithm>

struct digits_only: std::ctype<char> 
{
    digits_only(): std::ctype<char>(get_table()) {}

    static std::ctype_base::mask const* get_table()
    {
        static std::vector<std::ctype_base::mask> 
            rc(std::ctype<char>::table_size,std::ctype_base::space);

        if (rc['0'] == std::ctype_base::space)
            std::fill_n(&rc['0'], 9, std::ctype_base::mask());
        return &rc[0];
    }
};

Пример кода для использования может выглядеть следующим образом:

int main() {
    std::cin.imbue(std::locale(std::locale(), new digits_only()));

    std::copy(std::istream_iterator<int>(std::cin), 
        std::istream_iterator<int>(),
        std::ostream_iterator<int>(std::cout, "\n"));
}

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

46000
39850
38000

Обратите внимание, что я написал это так, чтобы принимать только цифр. Если (например) вы читаете числа с плавающей запятой, вы также хотели бы сохранить '.' (или эквивалентный локали эквивалент) в качестве десятичной точки. Один из способов справиться с ситуацией - начать с копии обычной таблицы ctype, а затем просто установить вещи, которые вы хотите игнорировать, как space.

0 голосов
/ 18 января 2010
fscanf(file, "%*s %d", &num);

или% 05d, если у вас начальные нули и фиксированная ширина 5 ....

иногда самый быстрый способ сделать что-то в C ++ - это использовать C.:)

0 голосов
/ 18 января 2010

здесь идет: P

private static void readFile(String fileName) {

        try {
            HashMap<String, Integer> map = new HashMap<String, Integer>();
            File file = new File(fileName);

            Scanner scanner = new Scanner(file).useDelimiter(";");
            while (scanner.hasNext()) {
                String token = scanner.next();
                String[] split = token.split(":");
                if (split.length == 2) {
                    Integer count = map.get(split[0]);
                    map.put(split[0], count == null ? 1 : count + 1);
                    System.out.println(split[0] + ":" + split[1]);
                } else {
                    split = token.split("=");
                    if (split.length == 2) {
                        Integer count = map.get(split[0]);
                        map.put(split[0], count == null ? 1 : count + 1);
                        System.out.println(split[0] + ":" + split[1]);
                    }
                }
            }
            scanner.close();
            System.out.println("Counts:" + map);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        readFile("test.txt");
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...