簡體   English   中英

讀取字符串 C++ 中的每個單詞

[英]Read every word in a string C++

我正在嘗試將每個單詞讀為一個字符串。 我想要一個字符串進入,第一個單詞出來,然后我會處理它,然后是第二個,依此類推。 但是互聯網並沒有幫助我,我知道它可能就在我的眼皮底下,但我想不通!

string lex(string filecontent) {

string t = filecontent;
getline(cin, t);

istringstream iss(t);
string word;

while (iss >> word) {
    return word;
}

}
int main() {
    string data = load_file(); // Returns a string of words
    cout << data;
    cout << lex(data);
    getchar();
}

現在這有效......它打印出很多隨機的胡言亂語和瘋狂的字符,我正在閱讀的文件的輸出沒問題,我在 cout << data 中檢查了這個,這正是我所期望的。 有任何想法嗎?

這是我認為您正在尋找的解決方案:

int main() {
   string data = load_file(); // Returns a string of words

   istringstream iss(data);

   while(iss)
   {
      string tok;
      iss >> tok;
      cout << "token: " << tok << endl;
      //you can do what ever you want with the token here

   }
}

看看這個,應該對你有幫助。

主程序

#include "stdafx.h"
#include "Utility.h"

int main() {
    using namespace util;

    std::string fileName( "sample.txt" );

    if ( fileName.empty() ) {
        std::cout << "Missing or invalid filename." << std::endl;
        return RETURN_ERROR;
    }

    std::string line;
    std::vector<std::string> results;
    std::fstream fin;

    // Try To Open File For Reading
    fin.open( fileName.c_str(), std::ios_base::in );
    if ( !fin.is_open() ) {
        std::cout << "Can not open file(" << fileName << ") for reading." << std::endl;
        return RETURN_ERROR;
    }

    // Read Line By Line To Get Data Contents Store Into String To Be Parsed
    while ( !fin.eof() ) {
        std::getline( fin, line );
        // Parse Each Line Using Space Character As Delimiter
        results = Utility::splitString( line, " " );

        // Print The Results On Each Iteration Of This While Loop 
        // This Is Where You Would Parse The Data Or Store Results Into
        // Class Objects, Variables Or Structures.
        for ( unsigned u = 0; u < results.size(); u++ ) {
            std::cout << results[u] << " ";
        }
        std::cout << std::endl;
    }

    // Close File Pointer
    fin.close();

    // Now Print The Full Vector Of Results - This Is To Show You That Each
    // New Line Will Be Overwritten And That Only The Last Line Of The File Will
    // Be Stored After The While Loop.
    std::cout << "\n-------------------------------------\n";
    for ( unsigned u = 0; u < results.size(); u++ ) {
        std::cout << results[u] << " ";
    }

    Utility::pressAnyKeyToQuit();
    return RETURN_OK;
} // main

樣本.txt

Please help me parse this text file
It spans multiple lines of text
I would like to get each individual word

stdafx.h - 其中一些包含文件可能不需要,因為我有一個更大的解決方案需要它們。

#ifndef STDAFX_H
#define STDAFX_H

#include <Windows.h>

#include <stdio.h>
#include <tchar.h>
#include <conio.h>

#include <string>
#include <sstream>
#include <fstream>
#include <iostream>
#include <iomanip>
#include <vector>
#include <array>
#include <memory>

#include <queue>
#include <functional>

#include <algorithm>

// User Application Specific
// #include "ExceptionHandler.h" - One Of My Class Objects Not Used Here

namespace util {

enum ReturnCode {
    RETURN_OK = 0,
    RETURN_ERROR = 1,
}; // ReturnCode

extern const unsigned INVALID_UNSIGNED;
extern const unsigned INVALID_UNSIGNED_SHORT;

} // namespace util

#endif // STDAFX_H

標准文件

#include "stdafx.h"

namespace util {

const unsigned INVALID_UNSIGNED = static_cast<const unsigned>( -1 );
const unsigned INVALID_UNSIGNED_SHORT = static_cast<const unsigned short>( -1 );

} // namespace util

實用程序.h

#ifndef UTILITY_H
#define UTILITY_H

namespace util {

class Utility {
public:

    static void pressAnyKeyToQuit();

    static std::string  toUpper(const std::string& str);
    static std::string  toLower(const std::string& str);
    static std::string  trim(const std::string& str, const std::string elementsToTrim = " \t\n\r");

    static unsigned     convertToUnsigned(const std::string& str);
    static int          convertToInt(const std::string& str);
    static float        convertToFloat(const std::string& str);

    static std::vector<std::string> splitString(const std::string& strStringToSplit, const std::string& strDelimiter, const bool keepEmpty = true);

private:
    Utility(); // Private - Not A Class Object
    Utility(const Utility& c); // Not Implemented
    Utility& operator=(const Utility& c); // Not Implemented

    template<typename T>
    static bool stringToValue(const std::string& str, T* pValue, unsigned uNumValues);

    template<typename T>
    static T getValue(const std::string& str, std::size_t& remainder);

}; // Utility

#include "Utility.inl"

} // namespace util

#endif // UTILITY_H

實用程序文件

// ----------------------------------------------------------------------------
// stringToValue()
template<typename T>
static bool Utility::stringToValue(const std::string& str, T* pValue, unsigned uNumValues) {
    int numCommas = std::count(str.begin(), str.end(), ',');
    if (numCommas != uNumValues - 1) {
        return false;
    }

    std::size_t remainder;
    pValue[0] = getValue<T>(str, remainder);

    if (uNumValues == 1) {
        if (str.size() != remainder) {
            return false;
        }
    }
    else {
        std::size_t offset = remainder;
        if (str.at(offset) != ',') {
            return false;
        }

        unsigned uLastIdx = uNumValues - 1;
        for (unsigned u = 1; u < uNumValues; ++u) {
            pValue[u] = getValue<T>(str.substr(++offset), remainder);
            offset += remainder;
            if ((u < uLastIdx && str.at(offset) != ',') ||
                (u == uLastIdx && offset != str.size()))
            {
                return false;
            }
        }
    }
    return true;
} // stringToValue

實用程序.cpp

#include "stdafx.h"
#include "Utility.h"

namespace util {

// ----------------------------------------------------------------------------
// pressAnyKeyToQuit()
void Utility::pressAnyKeyToQuit() {
    std::cout << "\nPress any key to quit" << std::endl;
    _getch();
} // pressAnyKeyToQuit

// ----------------------------------------------------------------------------
// toUpper()
std::string Utility::toUpper( const std::string& str ) {
    std::string result = str;
    std::transform( str.begin(), str.end(), result.begin(), ::toupper );
    return result;
} // toUpper

// ----------------------------------------------------------------------------
// toLower()
std::string Utility::toLower( const std::string& str ) {
    std::string result = str;
    std::transform( str.begin(), str.end(), result.begin(), ::tolower );
    return result;
} // toLower

// ----------------------------------------------------------------------------
// trim()
// Removes Elements To Trim From Left And Right Side Of The str
std::string Utility::trim( const std::string& str, const std::string elementsToTrim ) {
    std::basic_string<char>::size_type firstIndex = str.find_first_not_of( elementsToTrim );
    if ( firstIndex == std::string::npos ) {
        return std::string(); // Nothing Left
    }

    std::basic_string<char>::size_type lastIndex = str.find_last_not_of( elementsToTrim );
    return str.substr( firstIndex, lastIndex - firstIndex + 1 );
} // trim

// ----------------------------------------------------------------------------
// getValue()
template<>
float Utility::getValue( const std::string& str, std::size_t& remainder ) {
    return std::stof( str, &remainder );
} // getValue <float>

// ----------------------------------------------------------------------------
// getValue()
template<>
int Utility::getValue( const std::string& str, std::size_t& remainder ) {
    return std::stoi( str, &remainder );
} // getValue <int>

// ----------------------------------------------------------------------------
// getValue()
template<>
unsigned Utility::getValue( const std::string& str, std::size_t& remainder ) {
    return std::stoul( str, &remainder );
} // getValue <unsigned>

// ----------------------------------------------------------------------------
// convertToUnsigned()
unsigned Utility::convertToUnsigned( const std::string& str ) {
    unsigned u = 0;
    if ( !stringToValue( str, &u, 1 ) ) {
        std::ostringstream strStream;
        strStream << __FUNCTION__ << " Bad conversion of [" << str << "] to unsigned";
        throw strStream.str();
    }
    return u;
} // convertToUnsigned

// ----------------------------------------------------------------------------
// convertToInt()
int Utility::convertToInt( const std::string& str ) {
    int i = 0;
    if ( !stringToValue( str, &i, 1 ) ) {
        std::ostringstream strStream;
        strStream << __FUNCTION__ << " Bad conversion of [" << str << "] to int";
        throw strStream.str();
    }
    return i;
} // convertToInt

// ----------------------------------------------------------------------------
// convertToFloat()
float Utility::convertToFloat(const std::string& str) {
    float f = 0;
    if (!stringToValue(str, &f, 1)) {
        std::ostringstream strStream;
        strStream << __FUNCTION__ << " Bad conversion of [" << str << "] to float";
        throw strStream.str();
    }
    return f;
} // convertToFloat

// ----------------------------------------------------------------------------
// splitString()
std::vector<std::string> Utility::splitString( const std::string& strStringToSplit, const std::string& strDelimiter, const bool keepEmpty ) {
    std::vector<std::string> vResult;
    if ( strDelimiter.empty() ) {
        vResult.push_back( strStringToSplit );
        return vResult;
    }

    std::string::const_iterator itSubStrStart = strStringToSplit.begin(), itSubStrEnd;
    while ( true ) {
        itSubStrEnd = search( itSubStrStart, strStringToSplit.end(), strDelimiter.begin(), strDelimiter.end() );
        std::string strTemp( itSubStrStart, itSubStrEnd );
        if ( keepEmpty || !strTemp.empty() ) {
            vResult.push_back( strTemp );
        }

        if ( itSubStrEnd == strStringToSplit.end() ) {
            break;
        }

        itSubStrStart = itSubStrEnd + strDelimiter.size();
    }

    return vResult;

} // splitString

} // namspace util

在我的小型實用程序庫中,我有一個函數可以拆分可以使用用戶定義的任何分隔符的字符串。 它將搜索該字符定界符的第一次出現,並將其之前的所有內容保存到一個字符串中,並將該字符串推送到一個字符串向量中,並且它將在每次出現該字符時繼續執行此操作,直到完成解析傳遞給它的完整字符串。 然后它會將一個字符串向量返回給用戶。 這在解析文本文件或什至只是需要分解的長字符串數據類型時非常有用。 現在,如果您正在解析一個文本文件,並且假設您需要將多個單詞作為單個字符串,則可以這樣做,但需要您做更多的工作。 例如,文本文件可能在一行中包含個人記錄。

LastName, FirstName MiddleInitial Age Phone# Address
Cook, John S 33 1-888-323-4545 324 Complex Avenue

並且您希望 324 Complex Avenue 位於單個字符串中,並且您也不希望在姓氏之后存儲逗號。 用於存儲此信息的代碼結構可能如下所示:

struct PersonalRecord {
    std::string firstName;
    std::string lastName;
    char middleInitial;
    unsigned age;
    std::string phoneNumber;
    std:string address;
};

您需要做的是在 while 循環的同一次迭代中從您的文件中讀取此行之后,您將不得不進行多次解析。

您將首先使用臨時字符串和字符串向量開始,然后使用實用函數 splitString 並將分隔符作為逗號。 因此,這將在字符串的臨時向量中保存 2 個字符串,第一個是:Cook,第二個是逗號之后的其余行,包括前導空格。 您擁有臨時字符串和臨時字符串向量的原因是您需要在需要時彈出值。 因此,在這種情況下,我們必須執行以下操作,但首先我們如何將多個單詞解析為一個字符串的情況? 我們可以將文本文件中的文本行更改為用雙引號括起來,如下所示:

文本文件

Cook, John S 33 1-888-323-4545 "324 Complex Avenue"
Evens, Sue A 24 1-888-323-6996 "128 Mission Rd"
Adams, Chris B 49 1-777-293-8234 "2304 Helms Drive"

然后用這個邏輯流程或算法解析它。

主程序

#including "stdafx.h"
#including "Utility.h"

int main() {
    using namespace util;

    std::string strFilename( "personalRecord.txt" );
    std::ifstream file; 

    std::string strLine;
    std::vector<std::string> vTemp;
    std::vector<std::string> vResult;

    std::vector<PersonalRecord> vData;

    // Open File For Reading
    file.open( strFilename.c_str() );
    // Check For Error Of Opening File
    if ( !file.is_open() ) {
        std::cout << "Error opening file (" << strFilename << ")" << std::endl;
        return RETURN_ERROR;
    }

    // Continue Until End Of File
    while( !file.eof() ) {
        // Get Single Full Line Save To String
        std::getline( file, strLine );

        // Check For Comma
        vTemp = Utility::splitString( strLine, ",");
        // Save First String For Laster
        std::string lastName = vTemp[0];

        // Split String Using A Double Quote Delimiter Delimiter
        vTemp = Utility::splitString( vTemp[1], "\"" );

        // Check To See If vTemp Has More Than One String
        if ( vTemp.size() > 1 ) {
            // We Need To Use Pop Back To Account For Last Double Quote
            vTemp.pop_back(); // Remove Last Double Quote
            std::string temp = vTemp.back(); 
            vTemp.pop_back(); // Remove Wanted String From vTemp.

            // At This Point We Need To Parse vTemp Again Using Space Delimiter
            vResult = Utility::splitString( vTemp[0], " " );

            // Need To Account For Leading Space In Vector
            vResult[0].erase();
            // Need To Account For Last Space In Vector
            vResult.pop_back();

            // Now We Can Push Our Last String Back Into vResult
            vResult.push_back( temp );

            // Replace The First String " " With Our LastName
            vResult[0] = lastName;

        } else if ( vTemp.size() == 1 ) {
            // Just Parse vTemp Using Space Delimiter
            vResult = Utility::splitString( vTemp[0], " " );
        }


        // Print Out Results For Validity
        for ( unsigned u = 0; u < vResult.size(); u++) {
            std::cout << vResult.at(u) << " ";
        }
        std::cout << std::endl;

        // Here Is Where You Would Populate Your Variables, Structures Or Classes On Each Pass Of The While Loop.
        // With This Structure There Should Only Be 8 Entries Into Our vResult
        PersonalRecord temp;
        temp.lastName      = vResult[0];
        temp.firstName     = vResult[1];
        temp.middleInitial = vResult[2][0];
        temp.age           = Utility::convertToUnsigned( vResult[3] );
        temp.phoneNumber   = vResult[4];
        temp.address       = vResult[5];

        vData.push_back( temp );
    } // while

    // Close File
    file.close();

    std::cout << std::endl << std::endl;

    // Print Using Structure For Validity
    std::cout << "---------------------------------------\n";
    for ( unsigned u = 0; u < vData.size(); u++ ) {
        std::cout << vData[u].lastName << " " 
                  << vData[u].firstName << " "
                  << vData[u].middleInitial << " "
                  << vData[u].age << " "
                  << vData[u].phoneNumber << " "
                  << vData[u].address << std::endl;
    }

    Utility::pressAnyKeyToQuit();
    return RETURN_OK;
} // main

因此,在解析文本或字符串時,必須同時考慮 和 are。 您必須考慮每個字符,包括回車、空格等。因此必須考慮寫入文本文件的格式。 是的splitString()也將解析制表符,您只需要對制表符使用 "\\t" 等。請記住,它會在每次出現時進行拆分。 因此,如果您的句子中有一個冒號“:”,但是您決定使用冒號作為值之間的分隔符,它也會拆分該句子。 現在,您可以為文件中的每一行文本制定不同的規則,如果您知道自己在哪一行,則可以相應地解析每一行。 這就是為什么大多數人更喜歡編寫他們的代碼來讀取和解析二進制文件,因為它比編寫文本解析器更容易編程。

我選擇使用 PersonalRecord 結構向您展示如何從一行文本中提取字符串,並通過使用我的 Utility 類中的一些其他函數將它們轉換為基本類型,例如 int、float 或 double。 這個類中的所有方法都聲明為靜態的,構造函數是私有的,因此類名可以作為包裝器或命名空間。 您不能創建Utility util; // invalid object的實例Utility util; // invalid object Utility util; // invalid object 只需包含頭文件並使用類名和范圍解析運算符::來訪問任何函數,並確保您使用的是namespace util

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM