- C++ CSV Parser
- CsvFile.h
- CsvFile.cpp
- »ùÇÃ
1 C++ CSV Parser
- std::string ¹× std::vector¸¦ ÀÌ¿ëÇØ ±¸ÇöÇÑ ¼Ò½º´Ù. Visual C++ 8.0 ±âÁØÀ¸·Î ÀÛ¼ºÇß´Ù. º¤ÅÍ ÂÊÀÇ at() ÇÔ¼ö¸¸ ¼öÁ¤ÇÏ¸é ´Ù¸¥ Ç÷§Æû¿¡¼µµ º° ¹®Á¦¾øÀÌ ÄÄÆÄÀϵǸ®¶ó »ý°¢Çϴµ¥, ¾î¶³Áö´Â ¸ð¸£°Ú´Ù.
- ¿©·¯ ¶óÀο¡ °ÉÄ£ Ä÷³ °ªµµ Á¦´ë·Î ÆÄ½ÌÇÑ´Ù.
2 CsvFile.h
#ifndef __CSVFILE_H__
#define __CSVFILE_H__
#include <string>
#include <vector>
#if _MSC_VER
#include <hash_map>
#else
#include <map>
#endif
////////////////////////////////////////////////////////////////////////////////
/// \class cCsvAlias
/// \brief CSV ÆÄÀÏÀ» ¼öÁ¤ÇßÀ» ¶§ ¹ß»ýÇÏ´Â À妽º ¹®Á¦¸¦ ÁÙÀ̱â À§ÇÑ
/// º°¸í °´Ã¼.
///
/// ¿¹¸¦ µé¾î 0¹ø Ä÷³ÀÌ A¿¡ °üÇÑ ³»¿ëÀ» Æ÷ÇÔÇϰí, 1¹ø Ä÷³ÀÌ B¿¡ °üÇÑ ³»¿ëÀ»
/// Æ÷ÇÔÇϰí ÀÖ¾ú´Âµ¥...
///
/// <pre>
/// int a = row.AsInt(0);
/// int b = row.AsInt(1);
/// </pre>
///
/// ±× »çÀÌ¿¡ C¿¡ °üÇÑ ³»¿ëÀ» Æ÷ÇÔÇÏ´Â Ä÷³ÀÌ ³¢¾îµç °æ¿ì, ÇϵåÄÚµùµÇ¾î ÀÖ´Â
/// 1¹øÀ» ã¾Æ¼ °íÃÄ¾ß Çϴµ¥, »ó´çÈ÷ ¿¡·¯°¡ ¹ß»ýÇϱ⠽¬¿î ÀÛ¾÷ÀÌ´Ù.
///
/// <pre>
/// int a = row.AsInt(0);
/// int c = row.AsInt(1);
/// int b = row.AsInt(2); <-- ÀÌ ºÎºÐÀ» ÀÏÀÏÀÌ ½Å°æ½á¾ß ÇÑ´Ù.
/// </pre>
///
/// ÀÌ ºÎºÐÀ» ¹®ÀÚ¿·Î ó¸®Çϸé À¯Áöº¸¼ö¿¡ µé¾î°¡´Â ¼ö°í¸¦ ¾à°£À̳ª¸¶ ÁÙÀÏ ¼ö
/// ÀÖ´Ù.
////////////////////////////////////////////////////////////////////////////////
class cCsvAlias
{
private:
#if _MSC_VER
typedef stdext::hash_map<std::string, size_t> NAME2INDEX_MAP;
typedef stdext::hash_map<size_t, std::string> INDEX2NAME_MAP;
#else
typedef std::map<std::string, size_t> NAME2INDEX_MAP;
typedef std::map<size_t, std::string> INDEX2NAME_MAP;
#endif
NAME2INDEX_MAP m_Name2Index; ///< ¼¿ À妽º ´ë½ÅÀ¸·Î »ç¿ëÇϱâ À§ÇÑ À̸§µé
INDEX2NAME_MAP m_Index2Name; ///< À߸øµÈ alias¸¦ °Ë»çÇϱâ À§ÇÑ Ãß°¡ÀûÀÎ ¸Ê
public:
/// \brief »ý¼ºÀÚ
cCsvAlias() {}
/// \brief ¼Ò¸êÀÚ
virtual ~cCsvAlias() {}
public:
/// \brief ¼¿À» ¾×¼¼½ºÇÒ ¶§, ¼ýÀÚ ´ë½Å »ç¿ëÇÒ À̸§À» µî·ÏÇÑ´Ù.
void AddAlias(const char* name, size_t index);
/// \brief ¸ðµç µ¥ÀÌÅ͸¦ »èÁ¦ÇÑ´Ù.
void Destroy();
/// \brief ¼ýÀÚ À妽º¸¦ À̸§À¸·Î º¯È¯ÇÑ´Ù.
const char* operator [] (size_t index) const;
/// \brief À̸§À» ¼ýÀÚ À妽º·Î º¯È¯ÇÑ´Ù.
size_t operator [] (const char* name) const;
private:
/// \brief º¹»ç »ý¼ºÀÚ ±ÝÁö
cCsvAlias(const cCsvAlias&) {}
/// \brief ´ëÀÔ ¿¬»êÀÚ ±ÝÁö
const cCsvAlias& operator = (const cCsvAlias&) { return *this; }
};
////////////////////////////////////////////////////////////////////////////////
/// \class cCsvRow
/// \brief CSV ÆÄÀÏÀÇ ÇÑ ÇàÀ» ĸ½¶ÈÇÑ Å¬·¡½º
///
/// CSVÀÇ ±âº» Æ÷¸ËÀº ¿¢¼¿¿¡¼ º¸ÀÌ´Â ÇϳªÀÇ ¼¿À» ',' ¹®ÀÚ·Î ±¸ºÐÇÑ °ÍÀÌ´Ù.
/// ÇÏÁö¸¸, ¼¿ ¾È¿¡ Ư¼ö ¹®ÀÚ·Î ¾²ÀÌ´Â ',' ¹®ÀÚ³ª '"' ¹®ÀÚ°¡ µé¾î°¥ °æ¿ì,
/// ¸ð¾çÀÌ ¾à°£ ÀÌ»óÇÏ°Ô º¯ÇÑ´Ù. ´ÙÀ½Àº ±× º¯ÈÀÇ ¿¹ÀÌ´Ù.
///
/// <pre>
/// ¿¢¼¿¿¡¼ º¸ÀÌ´Â ¸ð¾ç | ½ÇÁ¦ CSV ÆÄÀÏ¿¡ µé¾î°¡ÀÖ´Â ¸ð¾ç
/// ---------------------+----------------------------------------------------
/// ItemPrice | ItemPrice
/// Item,Price | "Item,Price"
/// Item"Price | "Item""Price"
/// "ItemPrice" | """ItemPrice"""
/// "Item,Price" | """Item,Price"""
/// Item",Price | "Item"",Price"
/// </pre>
///
/// ÀÌ ¿¹·Î¼ ´ÙÀ½°ú °°Àº »çÇ×À» ¾Ë ¼ö ÀÖ´Ù.
/// - ¼¿ ³»ºÎ¿¡ ',' ¶Ç´Â '"' ¹®ÀÚ°¡ µé¾î°¥ °æ¿ì, ¼¿ Á¿쿡 '"' ¹®ÀÚ°¡ »ý±ä´Ù.
/// - ¼¿ ³»ºÎÀÇ '"' ¹®ÀÚ´Â 2°³·Î ġȯµÈ´Ù.
///
/// \sa cCsvFile
////////////////////////////////////////////////////////////////////////////////
class cCsvRow : public std::vector<std::string>
{
public:
/// \brief ±âº» »ý¼ºÀÚ
cCsvRow() {}
/// \brief ¼Ò¸êÀÚ
~cCsvRow() {}
public:
/// \brief ÇØ´ç ¼¿ÀÇ µ¥ÀÌÅ͸¦ int ÇüÀ¸·Î ¹ÝȯÇÑ´Ù.
int AsInt(size_t index) const { return atoi(at(index).c_str()); }
/// \brief ÇØ´ç ¼¿ÀÇ µ¥ÀÌÅ͸¦ double ÇüÀ¸·Î ¹ÝȯÇÑ´Ù.
double AsDouble(size_t index) const { return atof(at(index).c_str()); }
/// \brief ÇØ´ç ¼¿ÀÇ µ¥ÀÌÅ͸¦ ¹®ÀÚ¿·Î ¹ÝȯÇÑ´Ù.
const char* AsString(size_t index) const { return at(index).c_str(); }
/// \brief ÇØ´çÇÏ´Â À̸§ÀÇ ¼¿ µ¥ÀÌÅ͸¦ int ÇüÀ¸·Î ¹ÝȯÇÑ´Ù.
int AsInt(const char* name, const cCsvAlias& alias) const {
return atoi( at(alias[name]).c_str() );
}
/// \brief ÇØ´çÇÏ´Â À̸§ÀÇ ¼¿ µ¥ÀÌÅ͸¦ int ÇüÀ¸·Î ¹ÝȯÇÑ´Ù.
double AsDouble(const char* name, const cCsvAlias& alias) const {
return atof( at(alias[name]).c_str() );
}
/// \brief ÇØ´çÇÏ´Â À̸§ÀÇ ¼¿ µ¥ÀÌÅ͸¦ ¹®ÀÚ¿·Î ¹ÝȯÇÑ´Ù.
const char* AsString(const char* name, const cCsvAlias& alias) const {
return at(alias[name]).c_str();
}
private:
/// \brief º¹»ç »ý¼ºÀÚ ±ÝÁö
cCsvRow(const cCsvRow&) {}
/// \brief ´ëÀÔ ¿¬»êÀÚ ±ÝÁö
const cCsvRow& operator = (const cCsvRow&) { return *this; }
};
////////////////////////////////////////////////////////////////////////////////
/// \class cCsvFile
/// \brief CSV(Comma Seperated Values) ÆÄÀÏÀ» read/writeÇϱâ À§ÇÑ Å¬·¡½º
///
/// <b>sample</b>
/// <pre>
/// cCsvFile file;
///
/// cCsvRow row1, row2, row3;
/// row1.push_back("ItemPrice");
/// row1.push_back("Item,Price");
/// row1.push_back("Item\"Price");
///
/// row2.reserve(3);
/// row2[0] = "\"ItemPrice\"";
/// row2[1] = "\"Item,Price\"";
/// row2[2] = "Item\",Price\"";
///
/// row3 = "\"ItemPrice\"\"Item,Price\"Item\",Price\"";
///
/// file.add(row1);
/// file.add(row2);
/// file.add(row3);
/// file.save("test.csv", false);
/// </pre>
///
/// \todo ÆÄÀÏ¿¡¼¸¸ ÀоîµéÀÏ °ÍÀÌ ¾Æ´Ï¶ó, ¸Þ¸ð¸® ¼Ò½º·ÎºÎÅÍ Àд ÇÔ¼öµµ
/// ÀÖ¾î¾ß ÇÒ µí ÇÏ´Ù.
////////////////////////////////////////////////////////////////////////////////
class cCsvFile
{
private:
typedef std::vector<cCsvRow*> ROWS;
ROWS m_Rows; ///< Çà Ä÷º¼Ç
public:
/// \brief »ý¼ºÀÚ
cCsvFile() {}
/// \brief ¼Ò¸êÀÚ
virtual ~cCsvFile() { Destroy(); }
public:
/// \brief ÁöÁ¤µÈ À̸§ÀÇ CSV ÆÄÀÏÀ» ·ÎµåÇÑ´Ù.
bool Load(const char* fileName, const char seperator=',', const char quote='"');
/// \brief °¡Áö°í ÀÖ´Â ³»¿ëÀ» CSV ÆÄÀÏ¿¡´Ù ÀúÀåÇÑ´Ù.
bool Save(const char* fileName, bool append=false, char seperator=',', char quote='"') const;
/// \brief ¸ðµç µ¥ÀÌÅ͸¦ ¸Þ¸ð¸®¿¡¼ »èÁ¦ÇÑ´Ù.
void Destroy();
/// \brief ÇØ´çÇÏ´Â À妽ºÀÇ ÇàÀ» ¹ÝȯÇÑ´Ù.
cCsvRow* operator [] (size_t index);
/// \brief ÇØ´çÇÏ´Â À妽ºÀÇ ÇàÀ» ¹ÝȯÇÑ´Ù.
const cCsvRow* operator [] (size_t index) const;
/// \brief ÇàÀÇ °¹¼ö¸¦ ¹ÝȯÇÑ´Ù.
size_t GetRowCount() const { return m_Rows.size(); }
private:
/// \brief º¹»ç »ý¼ºÀÚ ±ÝÁö
cCsvFile(const cCsvFile&) {}
/// \brief ´ëÀÔ ¿¬»êÀÚ ±ÝÁö
const cCsvFile& operator = (const cCsvFile&) { return *this; }
};
////////////////////////////////////////////////////////////////////////////////
/// \class cCsvTable
/// \brief CSV ÆÄÀÏÀ» ÀÌ¿ëÇØ Å×ÀÌºí µ¥ÀÌÅ͸¦ ·ÎµåÇÏ´Â °æ¿ì°¡ ¸¹Àºµ¥, ÀÌ Å¬·¡½º´Â
/// ±× ÀÛ¾÷À» Á» ´õ ½±°Ô Çϱâ À§ÇØ ¸¸µç À¯Æ¿¸®Æ¼ Ŭ·¡½º´Ù.
///
/// CSV ÆÄÀÏÀ» ·ÎµåÇÏ´Â °æ¿ì, ¼ýÀÚ¸¦ ÀÌ¿ëÇØ ¼¿À» ¾×¼¼½ºÇØ¾ß Çϴµ¥, CSV
/// ÆÄÀÏÀÇ Æ÷¸ËÀÌ ¹Ù²î´Â °æ¿ì, ÀÌ ¼ýÀÚµéÀ» º¯°æÇØÁà¾ßÇÑ´Ù. ÀÌ ÀÛ¾÷ÀÌ ²Ï
/// ½Å°æ ÁýÁßÀ» ¿ä±¸ÇÏ´Â µ¥´Ù°¡, ¿¡·¯°¡ ¹ß»ýÇϱ⠽±´Ù. ±×·¯¹Ç·Î ¼ýÀÚ·Î
/// ¾×¼¼½ºÇϱ⺸´Ù´Â ¹®ÀÚ¿·Î ¾×¼¼½ºÇÏ´Â °ÍÀÌ ¾à°£ ´À¸®Áö¸¸ ³´´Ù°í ÇÒ ¼ö ÀÖ´Ù.
///
/// <b>sample</b>
/// <pre>
/// cCsvTable table;
///
/// table.alias(0, "ItemClass");
/// table.alias(1, "ItemType");
///
/// if (table.load("test.csv"))
/// {
/// while (table.next())
/// {
/// std::string item_class = table.AsString("ItemClass");
/// int item_type = table.AsInt("ItemType");
/// }
/// }
/// </pre>
////////////////////////////////////////////////////////////////////////////////
class cCsvTable
{
private:
cCsvFile m_File; ///< CSV ÆÄÀÏ °´Ã¼
cCsvAlias m_Alias; ///< ¹®ÀÚ¿À» ¼¿ À妽º·Î º¯È¯Çϱâ À§ÇÑ °´Ã¼
int m_CurRow; ///< ÇöÀç Ⱦ´Ü ÁßÀÎ Çà ¹øÈ£
public:
/// \brief »ý¼ºÀÚ
cCsvTable();
/// \brief ¼Ò¸êÀÚ
virtual ~cCsvTable();
public:
/// \brief ÁöÁ¤µÈ À̸§ÀÇ CSV ÆÄÀÏÀ» ·ÎµåÇÑ´Ù.
bool Load(const char* fileName, const char seperator=',', const char quote='"');
/// \brief ¼¿À» ¾×¼¼½ºÇÒ ¶§, ¼ýÀÚ ´ë½Å »ç¿ëÇÒ À̸§À» µî·ÏÇÑ´Ù.
void AddAlias(const char* name, size_t index) { m_Alias.AddAlias(name, index); }
/// \brief ´ÙÀ½ ÇàÀ¸·Î ³Ñ¾î°£´Ù.
bool Next();
/// \brief ÇöÀç ÇàÀÇ ¼¿ ¼ýÀÚ¸¦ ¹ÝȯÇÑ´Ù.
size_t ColCount() const;
/// \brief À妽º¸¦ ÀÌ¿ëÇØ int ÇüÀ¸·Î ¼¿°ªÀ» ¹ÝȯÇÑ´Ù.
int AsInt(size_t index) const;
/// \brief À妽º¸¦ ÀÌ¿ëÇØ double ÇüÀ¸·Î ¼¿°ªÀ» ¹ÝȯÇÑ´Ù.
double AsDouble(size_t index) const;
/// \brief À妽º¸¦ ÀÌ¿ëÇØ std::string ÇüÀ¸·Î ¼¿°ªÀ» ¹ÝȯÇÑ´Ù.
const char* AsString(size_t index) const;
/// \brief ¼¿ À̸§À» ÀÌ¿ëÇØ int ÇüÀ¸·Î ¼¿°ªÀ» ¹ÝȯÇÑ´Ù.
int AsInt(const char* name) const { return AsInt(m_Alias[name]); }
/// \brief ¼¿ À̸§À» ÀÌ¿ëÇØ double ÇüÀ¸·Î ¼¿°ªÀ» ¹ÝȯÇÑ´Ù.
double AsDouble(const char* name) const { return AsDouble(m_Alias[name]); }
/// \brief ¼¿ À̸§À» ÀÌ¿ëÇØ std::string ÇüÀ¸·Î ¼¿°ªÀ» ¹ÝȯÇÑ´Ù.
const char* AsString(const char* name) const { return AsString(m_Alias[name]); }
/// \brief alias¸¦ Æ÷ÇÔÇØ ¸ðµç µ¥ÀÌÅ͸¦ »èÁ¦ÇÑ´Ù.
void Destroy();
private:
/// \brief ÇöÀç ÇàÀ» ¹ÝȯÇÑ´Ù.
const cCsvRow* const CurRow() const;
/// \brief º¹»ç »ý¼ºÀÚ ±ÝÁö
cCsvTable(const cCsvTable&) {}
/// \brief ´ëÀÔ ¿¬»êÀÚ ±ÝÁö
const cCsvTable& operator = (const cCsvTable&) { return *this; }
};
#endif //__CSVFILE_H__
3 CsvFile.cpp
#include "CsvFile.h"
#include <fstream>
#ifndef Assert
#include <assert.h>
#define Assert assert
#define LogToFile (void)(0);
#endif
namespace
{
/// ÆÄ½Ì¿ë state ¿°Å°ª
enum ParseState
{
STATE_NORMAL = 0, ///< ÀÏ¹Ý »óÅÂ
STATE_QUOTE ///< µû¿ÈÇ¥ µÚÀÇ »óÅÂ
};
/// ¹®ÀÚ¿ Á¿ìÀÇ °ø¹éÀ» Á¦°ÅÇØ¼ ¹ÝȯÇÑ´Ù.
std::string Trim(std::string str)
{
str = str.erase(str.find_last_not_of(" \t\r\n") + 1);
str = str.erase(0, str.find_first_not_of(" \t\r\n"));
return str;
}
/// \brief ÁÖ¾îÁø ¹®Àå¿¡ ÀÖ´Â ¾ËÆÄºªÀ» ¸ðµÎ ¼Ò¹®ÀÚ·Î ¹Ù²Û´Ù.
std::string Lower(std::string original)
{
std::transform(original.begin(), original.end(), original.begin(), tolower);
return original;
}
}
////////////////////////////////////////////////////////////////////////////////
/// \brief ¼¿À» ¾×¼¼½ºÇÒ ¶§, ¼ýÀÚ ´ë½Å »ç¿ëÇÒ À̸§À» µî·ÏÇÑ´Ù.
/// \param name ¼¿ À̸§
/// \param index ¼¿ À妽º
////////////////////////////////////////////////////////////////////////////////
void cCsvAlias::AddAlias(const char* name, size_t index)
{
std::string converted(Lower(name));
Assert(m_Name2Index.find(converted) == m_Name2Index.end());
Assert(m_Index2Name.find(index) == m_Index2Name.end());
m_Name2Index.insert(NAME2INDEX_MAP::value_type(converted, index));
m_Index2Name.insert(INDEX2NAME_MAP::value_type(index, name));
}
////////////////////////////////////////////////////////////////////////////////
/// \brief ¸ðµç µ¥ÀÌÅ͸¦ »èÁ¦ÇÑ´Ù.
////////////////////////////////////////////////////////////////////////////////
void cCsvAlias::Destroy()
{
m_Name2Index.clear();
m_Index2Name.clear();
}
////////////////////////////////////////////////////////////////////////////////
/// \brief ¼ýÀÚ À妽º¸¦ À̸§À¸·Î º¯È¯ÇÑ´Ù.
/// \param index ¼ýÀÚ À妽º
/// \return const char* À̸§
////////////////////////////////////////////////////////////////////////////////
const char* cCsvAlias::operator [] (size_t index) const
{
INDEX2NAME_MAP::const_iterator itr(m_Index2Name.find(index));
if (itr == m_Index2Name.end())
{
LogToFile(NULL, "cannot find suitable conversion for %d", index);
Assert(false && "cannot find suitable conversion");
return NULL;
}
return itr->second.c_str();
}
////////////////////////////////////////////////////////////////////////////////
/// \brief À̸§À» ¼ýÀÚ À妽º·Î º¯È¯ÇÑ´Ù.
/// \param name À̸§
/// \return size_t ¼ýÀÚ À妽º
////////////////////////////////////////////////////////////////////////////////
size_t cCsvAlias::operator [] (const char* name) const
{
NAME2INDEX_MAP::const_iterator itr(m_Name2Index.find(Lower(name)));
if (itr == m_Name2Index.end())
{
LogToFile(NULL, "cannot find suitable conversion for %s", name);
Assert(false && "cannot find suitable conversion");
return 0;
}
return itr->second;
}
////////////////////////////////////////////////////////////////////////////////
/// \brief ÁöÁ¤µÈ À̸§ÀÇ CSV ÆÄÀÏÀ» ·ÎµåÇÑ´Ù.
/// \param fileName CSV ÆÄÀÏ À̸§
/// \param seperator ÇÊµå ºÐ¸®ÀÚ·Î »ç¿ëÇÒ ±ÛÀÚ. ±âº»°ªÀº ','ÀÌ´Ù.
/// \param quote µû¿ÈÇ¥·Î »ç¿ëÇÒ ±ÛÀÚ. ±âº»°ªÀº '"'ÀÌ´Ù.
/// \return bool ¹«»çÈ÷ ·ÎµåÇß´Ù¸é true, ¾Æ´Ï¶ó¸é false
////////////////////////////////////////////////////////////////////////////////
bool cCsvFile::Load(const char* fileName, const char seperator, const char quote)
{
Assert(seperator != quote);
std::ifstream file(fileName, std::ios::in);
if (!file) return false;
Destroy(); // ±âÁ¸ÀÇ µ¥ÀÌÅ͸¦ »èÁ¦
cCsvRow* row = NULL;
ParseState state = STATE_NORMAL;
std::string token = "";
char buf[2048+1] = {0,};
while (file.good())
{
file.getline(buf, 2048);
buf[sizeof(buf)-1] = 0;
std::string line(Trim(buf));
if (line.empty() || (state == STATE_NORMAL && line[0] == '#')) continue;
std::string text = std::string(line) + " "; // ÆÄ½Ì lookahead ¶§¹®¿¡ ºÙ¿©ÁØ´Ù.
size_t cur = 0;
while (cur < text.size())
{
// ÇöÀç ¸ðµå°¡ QUOTE ¸ðµåÀÏ ¶§,
if (state == STATE_QUOTE)
{
// '"' ¹®ÀÚÀÇ Á¾·ù´Â µÎ °¡ÁöÀÌ´Ù.
// 1. ¼¿ ³»ºÎ¿¡ Ư¼ö ¹®ÀÚ°¡ ÀÖÀ» °æ¿ì À̸¦ ¾Ë¸®´Â ¼¿ Á¿ìÀÇ °Í
// 2. ¼¿ ³»ºÎÀÇ '"' ¹®ÀÚ°¡ '"' 2°³·Î ġȯµÈ °Í
// ÀÌ Áß Ã¹¹øÂ° °æ¿ìÀÇ ÁÂÃø¿¡ ÀÖ´Â °ÍÀº CSV ÆÄÀÏÀÌ Á¤»óÀûÀ̶ó¸é,
// ¹«Á¶°Ç STATE_NORMAL¿¡ °É¸®°Ô µÇ¾îÀÖ´Ù.
// ±×·¯¹Ç·Î ¿©±â¼ °É¸®´Â °ÍÀº 1¹øÀÇ ¿ìÃø °æ¿ì³ª, 2¹ø °æ¿ì »ÓÀÌ´Ù.
// 2¹øÀÇ °æ¿ì¿¡´Â ¹«Á¶°Ç '"' ¹®ÀÚ°¡ 2°³¾¿ ³ªÅ¸³´Ù. ÇÏÁö¸¸ 1¹øÀÇ
// ¿ìÃø °æ¿ì¿¡´Â ¾Æ´Ï´Ù. À̸¦ ¹ÙÅÁÀ¸·Î ÇØ¼ Äڵ带 Â¥¸é...
if (text[cur] == quote)
{
// ´ÙÀ½ ¹®ÀÚ°¡ '"' ¹®ÀÚ¶ó¸é, Áï ¿¬¼ÓµÈ '"' ¹®ÀÚ¶ó¸é
// ÀÌ´Â ¼¿ ³»ºÎÀÇ '"' ¹®ÀÚ°¡ ġȯµÈ °ÍÀÌ´Ù.
if (text[cur+1] == quote)
{
token += quote;
++cur;
}
// ´ÙÀ½ ¹®ÀÚ°¡ '"' ¹®ÀÚ°¡ ¾Æ´Ï¶ó¸é
// ÇöÀçÀÇ '"'¹®ÀÚ´Â ¼¿ÀÇ ³¡À» ¾Ë¸®´Â ¹®ÀÚ¶ó°í ÇÒ ¼ö ÀÖ´Ù.
else
{
state = STATE_NORMAL;
}
}
else
{
token += text[cur];
}
}
// ÇöÀç ¸ðµå°¡ NORMAL ¸ðµåÀÏ ¶§,
else if (state == STATE_NORMAL)
{
if (row == NULL)
row = new cCsvRow();
// ',' ¹®ÀÚ¸¦ ¸¸³µ´Ù¸é ¼¿ÀÇ ³¡ÀÇ ÀǹÌÇÑ´Ù.
// ÅäÅ«À¸·Î¼ ¼¿ ¸®½ºÆ®¿¡´Ù°¡ Áý¾î³Ö°í, ÅäÅ«À» ÃʱâÈÇÑ´Ù.
if (text[cur] == seperator)
{
row->push_back(token);
token.clear();
}
// '"' ¹®ÀÚ¸¦ ¸¸³µ´Ù¸é, QUOTE ¸ðµå·Î ÀüȯÇÑ´Ù.
else if (text[cur] == quote)
{
state = STATE_QUOTE;
}
// ´Ù¸¥ ÀÏ¹Ý ¹®ÀÚ¶ó¸é ÇöÀç ÅäÅ«¿¡´Ù°¡ µ¡ºÙÀδÙ.
else
{
token += text[cur];
}
}
++cur;
}
// ¸¶Áö¸· ¼¿Àº ³¡¿¡ ',' ¹®ÀÚ°¡ ¾ø±â ¶§¹®¿¡ ¿©±â¼ Ãß°¡ÇØÁà¾ßÇÑ´Ù.
// ´Ü, óÀ½¿¡ ÆÄ½Ì lookahead ¶§¹®¿¡ ºÙÀÎ ½ºÆäÀ̽º ¹®ÀÚ µÎ °³¸¦ ¶¾´Ù.
if (state == STATE_NORMAL)
{
Assert(row != NULL);
row->push_back(token.substr(0, token.size()-2));
m_Rows.push_back(row);
token.clear();
row = NULL;
}
else
{
token = token.substr(0, token.size()-2) + "\r\n";
}
}
return true;
}
////////////////////////////////////////////////////////////////////////////////
/// \brief °¡Áö°í ÀÖ´Â ³»¿ëÀ» CSV ÆÄÀÏ¿¡´Ù ÀúÀåÇÑ´Ù.
/// \param fileName CSV ÆÄÀÏ À̸§
/// \param append trueÀÏ °æ¿ì, ±âÁ¸ÀÇ ÆÄÀÏ¿¡´Ù µ¡ºÙÀδÙ. falseÀÎ °æ¿ì¿¡´Â
/// ±âÁ¸ÀÇ ÆÄÀÏ ³»¿ëÀ» »èÁ¦Çϰí, »õ·Î ¾´´Ù.
/// \param seperator ÇÊµå ºÐ¸®ÀÚ·Î »ç¿ëÇÒ ±ÛÀÚ. ±âº»°ªÀº ','ÀÌ´Ù.
/// \param quote µû¿ÈÇ¥·Î »ç¿ëÇÒ ±ÛÀÚ. ±âº»°ªÀº '"'ÀÌ´Ù.
/// \return bool ¹«»çÈ÷ ÀúÀåÇß´Ù¸é true, ¿¡·¯°¡ »ý±ä °æ¿ì¿¡´Â false
////////////////////////////////////////////////////////////////////////////////
bool cCsvFile::Save(const char* fileName, bool append, char seperator, char quote) const
{
Assert(seperator != quote);
// Ãâ·Â ¸ðµå¿¡ µû¶ó ÆÄÀÏÀ» Àû´çÇÑ Ç÷¡±×·Î »ý¼ºÇÑ´Ù.
std::ofstream file;
if (append) { file.open(fileName, std::ios::out | std::ios::app); }
else { file.open(fileName, std::ios::out | std::ios::trunc); }
// ÆÄÀÏÀ» ¿Áö ¸øÇß´Ù¸é, false¸¦ ¸®ÅÏÇÑ´Ù.
if (!file) return false;
char special_chars[5] = { seperator, quote, '\r', '\n', 0 };
char quote_escape_string[3] = { quote, quote, 0 };
// ¸ðµç ÇàÀ» Ⱦ´ÜÇϸé¼...
for (size_t i=0; i<m_Rows.size(); i++)
{
const cCsvRow& row = *((*this)[i]);
std::string line;
// Çà ¾ÈÀÇ ¸ðµç ÅäÅ«À» Ⱦ´ÜÇϸé¼...
for (size_t j=0; j<row.size(); j++)
{
const std::string& token = row[j];
// ÀϹÝÀûÀÎ('"' ¶Ç´Â ','¸¦ Æ÷ÇÔÇÏÁö ¾ÊÀº)
// ÅäÅ«À̶ó¸é ±×³É ÀúÀåÇÏ¸é µÈ´Ù.
if (token.find_first_of(special_chars) == std::string::npos)
{
line += token;
}
// Ư¼ö¹®ÀÚ¸¦ Æ÷ÇÔÇÑ ÅäÅ«À̶ó¸é ¹®ÀÚ¿ Á¿쿡 '"'¸¦ ºÙ¿©ÁÖ°í,
// ¹®ÀÚ¿ ³»ºÎÀÇ '"'¸¦ µÎ °³·Î ¸¸µé¾îÁà¾ßÇÑ´Ù.
else
{
line += quote;
for (size_t k=0; k<token.size(); k++)
{
if (token[k] == quote) line += quote_escape_string;
else line += token[k];
}
line += quote;
}
// ¸¶Áö¸· ¼¿ÀÌ ¾Æ´Ï¶ó¸é ','¸¦ ÅäÅ«ÀÇ µÚ¿¡´Ù ºÙ¿©Áà¾ßÇÑ´Ù.
if (j != row.size() - 1) { line += seperator; }
}
// ¶óÀÎÀ» Ãâ·ÂÇÑ´Ù.
file << line << std::endl;
}
return true;
}
////////////////////////////////////////////////////////////////////////////////
/// \brief ¸ðµç µ¥ÀÌÅ͸¦ ¸Þ¸ð¸®¿¡¼ »èÁ¦ÇÑ´Ù.
////////////////////////////////////////////////////////////////////////////////
void cCsvFile::Destroy()
{
for (ROWS::iterator itr(m_Rows.begin()); itr != m_Rows.end(); ++itr)
delete *itr;
m_Rows.clear();
}
////////////////////////////////////////////////////////////////////////////////
/// \brief ÇØ´çÇÏ´Â À妽ºÀÇ ÇàÀ» ¹ÝȯÇÑ´Ù.
/// \param index À妽º
/// \return cCsvRow* ÇØ´ç Çà
////////////////////////////////////////////////////////////////////////////////
cCsvRow* cCsvFile::operator [] (size_t index)
{
Assert(index < m_Rows.size());
return m_Rows[index];
}
////////////////////////////////////////////////////////////////////////////////
/// \brief ÇØ´çÇÏ´Â À妽ºÀÇ ÇàÀ» ¹ÝȯÇÑ´Ù.
/// \param index À妽º
/// \return const cCsvRow* ÇØ´ç Çà
////////////////////////////////////////////////////////////////////////////////
const cCsvRow* cCsvFile::operator [] (size_t index) const
{
Assert(index < m_Rows.size());
return m_Rows[index];
}
////////////////////////////////////////////////////////////////////////////////
/// \brief »ý¼ºÀÚ
////////////////////////////////////////////////////////////////////////////////
cCsvTable::cCsvTable()
: m_CurRow(-1)
{
}
////////////////////////////////////////////////////////////////////////////////
/// \brief ¼Ò¸êÀÚ
////////////////////////////////////////////////////////////////////////////////
cCsvTable::~cCsvTable()
{
}
////////////////////////////////////////////////////////////////////////////////
/// \brief ÁöÁ¤µÈ À̸§ÀÇ CSV ÆÄÀÏÀ» ·ÎµåÇÑ´Ù.
/// \param fileName CSV ÆÄÀÏ À̸§
/// \param seperator ÇÊµå ºÐ¸®ÀÚ·Î »ç¿ëÇÒ ±ÛÀÚ. ±âº»°ªÀº ','ÀÌ´Ù.
/// \param quote µû¿ÈÇ¥·Î »ç¿ëÇÒ ±ÛÀÚ. ±âº»°ªÀº '"'ÀÌ´Ù.
/// \return bool ¹«»çÈ÷ ·ÎµåÇß´Ù¸é true, ¾Æ´Ï¶ó¸é false
////////////////////////////////////////////////////////////////////////////////
bool cCsvTable::Load(const char* fileName, const char seperator, const char quote)
{
Destroy();
return m_File.Load(fileName, seperator, quote);
}
////////////////////////////////////////////////////////////////////////////////
/// \brief ´ÙÀ½ ÇàÀ¸·Î ³Ñ¾î°£´Ù.
/// \return bool ´ÙÀ½ ÇàÀ¸·Î ¹«»çÈ÷ ³Ñ¾î°£ °æ¿ì true¸¦ ¹ÝȯÇϰí, ´õ ÀÌ»ó
/// ³Ñ¾î°¥ ÇàÀÌ Á¸ÀçÇÏÁö ¾Ê´Â °æ¿ì¿¡´Â false¸¦ ¹ÝȯÇÑ´Ù.
////////////////////////////////////////////////////////////////////////////////
bool cCsvTable::Next()
{
// 20¾ï¹ø Á¤µµ È£ÃâÇÏ¸é ¿À¹öÇ÷ΰ¡ ÀϾÅÙµ¥...±¦Âú°ÚÁö?
return ++m_CurRow < (int)m_File.GetRowCount() ? true : false;
}
////////////////////////////////////////////////////////////////////////////////
/// \brief ÇöÀç ÇàÀÇ ¼¿ ¼ýÀÚ¸¦ ¹ÝȯÇÑ´Ù.
/// \return size_t ÇöÀç ÇàÀÇ ¼¿ ¼ýÀÚ
////////////////////////////////////////////////////////////////////////////////
size_t cCsvTable::ColCount() const
{
return CurRow()->size();
}
////////////////////////////////////////////////////////////////////////////////
/// \brief À妽º¸¦ ÀÌ¿ëÇØ int ÇüÀ¸·Î ¼¿ °ªÀ» ¹ÝȯÇÑ´Ù.
/// \param index ¼¿ À妽º
/// \return int ¼¿ °ª
////////////////////////////////////////////////////////////////////////////////
int cCsvTable::AsInt(size_t index) const
{
const cCsvRow* const row = CurRow();
Assert(row);
Assert(index < row->size());
return row->AsInt(index);
}
////////////////////////////////////////////////////////////////////////////////
/// \brief À妽º¸¦ ÀÌ¿ëÇØ double ÇüÀ¸·Î ¼¿ °ªÀ» ¹ÝȯÇÑ´Ù.
/// \param index ¼¿ À妽º
/// \return double ¼¿ °ª
////////////////////////////////////////////////////////////////////////////////
double cCsvTable::AsDouble(size_t index) const
{
const cCsvRow* const row = CurRow();
Assert(row);
Assert(index < row->size());
return row->AsDouble(index);
}
////////////////////////////////////////////////////////////////////////////////
/// \brief À妽º¸¦ ÀÌ¿ëÇØ std::string ÇüÀ¸·Î ¼¿ °ªÀ» ¹ÝȯÇÑ´Ù.
/// \param index ¼¿ À妽º
/// \return const char* ¼¿ °ª
////////////////////////////////////////////////////////////////////////////////
const char* cCsvTable::AsString(size_t index) const
{
const cCsvRow* const row = CurRow();
Assert(row);
Assert(index < row->size());
return row->AsString(index);
}
////////////////////////////////////////////////////////////////////////////////
/// \brief alias¸¦ Æ÷ÇÔÇØ ¸ðµç µ¥ÀÌÅ͸¦ »èÁ¦ÇÑ´Ù.
////////////////////////////////////////////////////////////////////////////////
void cCsvTable::Destroy()
{
m_File.Destroy();
m_Alias.Destroy();
m_CurRow = -1;
}
////////////////////////////////////////////////////////////////////////////////
/// \brief ÇöÀç ÇàÀ» ¹ÝȯÇÑ´Ù.
/// \return const cCsvRow* ¾×¼¼½º°¡ °¡´ÉÇÑ ÇöÀç ÇàÀÌ Á¸ÀçÇÏ´Â °æ¿ì¿¡´Â ±× ÇàÀÇ
/// Æ÷ÀÎÅ͸¦ ¹ÝȯÇϰí, ´õ ÀÌ»ó ¾×¼¼½º °¡´ÉÇÑ ÇàÀÌ ¾ø´Â °æ¿ì¿¡´Â NULLÀ»
/// ¹ÝȯÇÑ´Ù.
////////////////////////////////////////////////////////////////////////////////
const cCsvRow* const cCsvTable::CurRow() const
{
if (m_CurRow < 0)
{
Assert(false && "call Next() first!");
return NULL;
}
else if (m_CurRow >= (int)m_File.GetRowCount())
{
Assert(false && "no more rows!");
return NULL;
}
return m_File[m_CurRow];
}
4 »ùÇÃ
int main()
{
cCsvTable table;
if (!table.Load("file.csv"))
return -1;
table.AddAlias("First", 0);
table.AddAlias("Second", 1);
table.AddAlias("Third", 2);
while (table.Next())
{
int first = table.AsInt("First");
int second = table.AsInt("Second");
std::string third = table.AsString("Third"));
}
return 0;
}
SeriousMoin v1 (koMoinMoin 1.0a4 Modified)