ج ++ ملف الإعلام والتوعية وعن طريق تقسيم فاصل

StackOverflow https://stackoverflow.com/questions/267427

  •  06-07-2019
  •  | 
  •  

سؤال

ولدي ملف مع البيانات المدرجة على النحو التالي:

0,       2,    10
10,       8,    10
10,       10,   10
10,       16,   10
15,       10,   16
17,       10,   16

وأريد أن أكون قادرة على إدخال الملف وتقسيمه إلى ثلاثة صفوف، في عملية تقليم جميع المساحات الزائدة وتحويل كل عنصر إلى أعداد صحيحة.

لسبب ما لا أستطيع أن أجد وسيلة سهلة للقيام بذلك في ج ++. نجاح الوحيد لقد كان هو عن طريق إدخال كل سطر في صفيف، ثم regexing من جميع المساحات وثم تقسيمه. أخذت هذه العملية برمتها لي جيدة 20-30 خطوط رمز ولها من الألم لتعديل لنقول فاصل آخر (على سبيل المثال الفضاء)، وغيرها.

وهذا هو ما يعادل بيثون ما أود أن يكون في C ++:

f = open('input_hard.dat')
lines =  f.readlines()
f.close()

#declarations
inint, inbase, outbase = [], [], []

#input parsing
for line in lines:
    bits = string.split(line, ',')
    inint.append(int(bits[0].strip()))
    inbase.append(int(bits[1].strip()))
    outbase.append(int(bits[2].strip()))

وسهولة الاستخدام للقيام بذلك في بيثون هي واحدة من الأسباب التي انتقلت إليها في المقام الأول. ومع ذلك، أحتاج إلى القيام بذلك في C ++ الآن، وأنا أكره أن لديك لاستخدام بلدي القبيح كود 20-30 الخط.

وأي مساعدة سيكون موضع تقدير، وذلك بفضل!

هل كانت مفيدة؟

المحلول

وهناك حقا شيء خاطئ مع fscanf، الذي هو على الارجح أسرع حل في هذه الحالة. وانها كما قصيرة ويمكن قراءتها كما رمز الثعبان:

FILE *fp = fopen("file.dat", "r");
int x, y, z;
std::vector<int> vx, vy, vz;

while (fscanf(fp, "%d, %d, %d", &x, &y, &z) == 3) {
  vx.push_back(x);
  vy.push_back(y);
  vz.push_back(z);
}
fclose(fp);

نصائح أخرى

وليس هناك حاجة حقيقية لاستخدام دفعة في هذا المثال كما تيارات سوف تفعل خدعة لطيف:

int main(int argc, char* argv[])
{
    ifstream file(argv[1]);

    const unsigned maxIgnore = 10;
    const int delim = ',';
    int x,y,z;

    vector<int> vecx, vecy, vecz;

    while (file)
    {
        file >> x;
        file.ignore(maxIgnore, delim);
        file >> y;
        file.ignore(maxIgnore, delim);
        file >> z;

        vecx.push_back(x);
        vecy.push_back(y);
        vecz.push_back(z);
    }
}

وعلى الرغم من أن لو كنت تنوي استخدام دفعة كنت تفضل بساطة <لأ href = "http://www.boost.org/doc/libs/1_37_0/libs/tokenizer/tokenizer.htm" يختلط = " noreferrer "> tokenizer لREGEX ...:)

وشيء من هذا القبيل:

vector<int> inint;
vector<int> inbase;
vector<int> outbase;
while (fgets(buf, fh)) {
   char *tok = strtok(buf, ", ");
   inint.push_back(atoi(tok));
   tok = strtok(NULL, ", ");
   inbase.push_back(atoi(tok));
   tok = strtok(NULL, ", ");
   outbase.push_back(atoi(tok));
}

وإلا مع التحقق من الخطأ.

والأمراض المنقولة جنسيا :: getline يسمح لك قراءة سطر من النص، ويمكنك استخدام تيار سلسلة تحليل خط الفردية:

string buf;
getline(cin, buf); 
stringstream par(buf);

char buf2[512];
par.getline(buf2, 512, ','); /* Reads until the first token. */

وبمجرد الحصول على سطر من النص في سلسلة، يمكنك فعلا استخدام أي وظيفة التوزيع تريد، حتى sscanf (buf.c_str ()، "٪ د،٪ د '٪ د"، وI1، وشركة i2، وكور i3) ، وذلك باستخدام atoi على سلسلة فرعية مع عدد صحيح، أو من خلال بعض الطرق الأخرى.

ويمكنك أيضا تجاهل الشخصيات غير المرغوب فيها في تيار المدخلات، وإذا كنت تعرف انهم هناك:

if (cin.peek() == ',')
    cin.ignore(1, ',');
cin >> nextInt;  

إذا كنت لا تمانع في استخدام المكتبات تفعيل ...

#include <string>
#include <vector>
#include <boost/lexical_cast.hpp>
#include <boost/regex.hpp>

std::vector<int> ParseFile(std::istream& in) {
    const boost::regex cItemPattern(" *([0-9]+),?");
    std::vector<int> return_value;

    std::string line;
    while (std::getline(in, line)) {
        string::const_iterator b=line.begin(), e=line.end();
        boost::smatch match;
        while (b!=e && boost::regex_search(b, e, match, cItemPattern)) {
            return_value.push_back(boost::lexical_cast<int>(match[1].str()));
            b=match[0].second;
        };
    };

    return return_value;
}

وهذا يسحب خطوط من تيار، ثم يستخدم دفعة :: مكتبة التعبير العادي (مع مجموعة القبض) لاستخراج كل عدد من الخطوط. يتجاهل تلقائيا كل ما هو ليس رقم صالح، على الرغم من أن يمكن أن تتغير إذا كنت ترغب في ذلك.

وانها لا تزال حوالي عشرين خطوط مع #includes، ولكن يمكنك استخدامها لاستخراج أساسا <م> أي شيء من خطوط الملف. هذا هو المثال تافهة، أنا باستخدام كود حد كبير متطابقة لاستخراج العلامات والقيم اختياري من حقل قاعدة بيانات، والفرق الرئيسي الوحيد هو التعبير العادي.

وتحرير: عفوا، أردت ثلاث ناقلات منفصلة. جرب هذا تعديل طفيف بدلا من ذلك:

const boost::regex cItemPattern(" *([0-9]+), *([0-9]+), *([0-9]+)");
std::vector<int> vector1, vector2, vector3;

std::string line;
while (std::getline(in, line)) {
    string::const_iterator b=line.begin(), e=line.end();
    boost::smatch match;
    while (b!=e && boost::regex_search(b, e, match, cItemPattern)) {
        vector1.push_back(boost::lexical_cast<int>(match[1].str()));
        vector2.push_back(boost::lexical_cast<int>(match[2].str()));
        vector3.push_back(boost::lexical_cast<int>(match[3].str()));
        b=match[0].second;
    };
};

لماذا لا نفس الرمز كما هو الحال في بيثون :)؟

std::ifstream file("input_hard.dat");
std::vector<int> inint, inbase, outbase;

while (file.good()){
    int val1, val2, val3;
    char delim;
    file >> val1 >> delim >> val2 >> delim >> val3;

    inint.push_back(val1);
    inbase.push_back(val2);
    outbase.push_back(val3);
}

إذا كنت تريد أن تكون قادرة على النطاق لنماذج المدخلات أصعب، يجب عليك أن تنظر الروح، مكتبة دفعة محلل combinator.

هذه الصفحة لديها على سبيل المثال التي تفعل تقريبا ما تحتاج (مع ريال وناقلات واحد على الرغم من)

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top