在c ++中解析/拆分const char *

时间:2017-06-08 09:23:44

标签: c++ parsing

我试图找到一个解决方案,但我找不到任何解决我问题的方法。

我有一个C ++程序,它接收;WITH CTE AS( SELECT *, ROW_NUMBER() OVER(PARTITION BY o.id ORDER BY r.datetime) RN FROM vw_UserView_OpenAndClosed2016 o INNER JOIN dbo.tblcallev r ON r.callid = o.id and r.eventtype = 1081 WHERE o.SchemeName = 'INDIS' AND o.SubSymptom = 'Care' AND Closed is NULL ) SELECT * FROM CTE WHERE RN=1 变量(const char*)和大小(filedata)。此变量的内容为 csv格式。每个字段用';'分隔。内容也是动态的,并且可能具有更多或更少的内容,因为此变量表示一组日志。还有一个分隔符filesize来表示换行符。

filedata的示例1:

\n

fildedata示例2:

const char* filedata =
    "1496843100;2017-06-07 13:45:00;000002D8;2800;0x23000CCD.VARIABLE67\n"
    "1496843100;2017-06-07 13:45:00;000002D9;2800;0x23000CCD.VARIABLE68";

如果您看到示例1只有2行,示例2有3行。我不知道我有多少行。我可以有2,3,200,1000等行,const char* filedata = "1496843100;2017-06-07 13:45:00;000002D8;2800;0x23000CCD.VARIABLE67\n" "1496843100;2017-06-07 13:45:00;000002D9;2800;0x23000CCD.VARIABLE68\n" "1496843100;2017-06-07 13:45:00;000002DA;2800;0x23000CCD.VARIABLE69"; 变量保存所有内容。

所以我的目标是接收这个filedata变量(我也可以访问filesize),对于每行我需要解析字段 1和2 (时间戳和数据)正常格式)。

预期输出(对于示例2):

filedata

在示例2中,我有3行,所以我需要迭代所有行,并且每行解析特定字段,非常类似于输出。 在此之后,我选择每个解析器字段并保存到对象列表(这部分已经实现。我只是在解析1496843100 2017-06-07 13:45:00 1496843100 2017-06-07 13:45:00 1496843100 2017-06-07 13:45:00 时遇到了问题。

5 个答案:

答案 0 :(得分:0)

您可以使用此正则表达式

const char *regex_str  = "\\d{10};[\\d,-]{10} [\\d,:]{8}"; //verified in http://regexr.com/

然后从您的输入const char *中找到所有正则表达式 - 从finding all regex获取帮助 - 用于Windows。

在mac os std :: regex中可能无法直接使用。需要在命令行中添加-stdlib=libc++

答案 1 :(得分:0)

这是使用您想要的输出的工作代码。我将这个SO answer用于我在重复标记中引用的SO问题。我对其进行了修改,以便新行字符\n也可以作为分隔符。因此在代码中有两个while循环。

您必须将要拥有的列数(cols)传递给split()函数。您也可以(可选)传递应排除的列(filtCol)。代码下的示例使用:cols = 5filtCols = (1 << 1) | (1 << 3),这意味着除了第2列和第4列之外,所有五列都应该被解析。仅仅第1,3和5列在结果向量中。我使用了一点模式,因为它的评估速度比列表/数组更快。

#include <string>
#include <sstream>
#include <vector>
#include <iterator>
#include <iostream>

template<typename Out>
void split(const std::string& s, char delim, size_t cols, size_t filtCol, Out result)
{
   std::stringstream ss;
   ss.str(s);
   std::string item;

   /* Two while loops two separate on new line first */
   while (std::getline(ss, item))
   {
      std::stringstream ssLine;
      ssLine.str(item);
      std::string itemLine;

      /* Parse line and separate */
      size_t curCol = 0;
      while (std::getline(ssLine, itemLine, delim))
      {
         /* Just add column is in range and is not excluded by */
         /* bit pattern!                                       */
         if (curCol < cols && (~filtCol & (1 << curCol)))
         {
            *(result++) = itemLine;
         }

         ++curCol;
      }
   }
}

std::vector<std::string> split(const std::string& s, char delim, size_t cols, size_t filtCol = 0)
{
   std::vector<std::string> elems;
   split(s, delim, cols, filtCol, std::back_inserter(elems));
   return elems;
}

/* Example usage */
int main()
{
   const char* filedataI =
       "1496843100;2017-06-07 13:45:00;000002D8;2800;0x23000CCD.VARIABLE67\n"
       "1496843100;2017-06-07 13:45:00;000002D9;2800;0x23000CCD.VARIABLE68\n"
       "1496843100;2017-06-07 13:45:00;000002DA;2800;0x23000CCD.VARIABLE69";

   size_t colsRange = 5; /* Parse from col 1 to 5 (all five) */
   size_t colsFiltered = (1 << 1) | (1 << 3); /* Exclude col 2 and 4 */
   size_t colsPerLine = 3; /* 5 - 2 = 3 */

   std::vector<std::string> strVecI = split(filedataI, ';', colsRange, colsFiltered);
   for (size_t idx = 0; idx < strVecI.size(); ++idx)
   {
      if (idx > 0 && 0 == idx % colsPerLine)
      {
         std::cout << std::endl;
      }
      std::cout << "\"" << strVecI[idx] << "\" " << " ";
   }
}

需要3列的输出(5个,其中2个被排除:cols = 5filtCols = (1 << 1) | (1 << 3)),我还打印了"和其间的三个空格:

"1496843100"  "000002D8"  "0x23000CCD.VARIABLE67"  
"1496843100"  "000002D9"  "0x23000CCD.VARIABLE68"  
"1496843100"  "000002DA"  "0x23000CCD.VARIABLE69"

答案 2 :(得分:0)

使用<regex>
regex_token_iterator作为拆分器

首先分为\n;

代码:

const char* filedata =
    "1496843100;2017-06-07 13:45:00;000002D8;2800;0x23000CCD.VARIABLE67\n"
    "1496843100;2017-06-07 13:45:00;000002D9;2800;0x23000CCD.VARIABLE68\n"
    "1496843100;2017-06-07 13:45:00;000002DA;2800;0x23000CCD.VARIABLE69";

const char* begin_f = filedata;
const char* end___f = filedata + std::string( filedata ).size();

/* first of all split by newline */

std::vector< std::string > vec_str;
std::regex regex1( "\n" );
std::regex regex2( ";" );

std::regex_token_iterator< const char* > first( begin_f, end___f, regex1, -1 ), last;
vec_str.assign( first, last );

for( std::string str1 : vec_str ){

    /* then split by semicolon ; */
    std::regex_token_iterator< std::string::const_iterator > first( str1.begin(),str1.end(), regex2, -1 ), last;
    int counter = 2;
    while( first != last && counter-- ){
        std::cout << *first++ << " ";
    }
    std::cout << '\n';

}

输出:

1496843100 2017-06-07 13:45:00 
1496843100 2017-06-07 13:45:00 
1496843100 2017-06-07 13:45:00

答案 3 :(得分:0)

这是使用std::find()的解决方案,应该非常快速有效。我的想法是你有一个外部循环,找到每个连续的行结束'\n'和一个内部循环,找到(在该范围内)每个连续的字段结束';'

在两个循环的核心,你有机会用列做任何你喜欢的事情:

char const* filedata =
    "1496843100;2017-06-07 13:45:00;000002D8;2800;0x23000CCD.VARIABLE67\n"
    "1496843100;2017-06-07 13:45:00;000002D9;2800;0x23000CCD.VARIABLE68\n"
    "1496843100;2017-06-07 13:45:00;000002DA;2800;0x23000CCD.VARIABLE69";

auto filesize = std::strlen(filedata);

auto line_beg = filedata;
auto line_end = filedata + filesize;

for(; auto line_pos = std::find(line_beg, line_end, '\n'); line_beg = line_pos + 1)
{
    auto field_beg = line_beg;
    auto field_end = line_pos;

    auto field_number = 0U;
    for(; auto field_pos = std::find(field_beg, field_end, ';'); field_beg = field_pos + 1)
    {
        ++field_number;

        // select the field number you want here
        if(field_number == 1 || field_number == 2)
        {
            // do something with the field that starts at field_beg
            // and ends at field_pos 
            std::cout << ' ' << std::string(field_beg, field_pos);
        }

        if(field_pos == field_end)
            break;
    }

    std::cout << '\n';

    if(line_pos == line_end)
        break;
}

<强>输出:

 1496843100 2017-06-07 13:45:00
 1496843100 2017-06-07 13:45:00
 1496843100 2017-06-07 13:45:00

答案 4 :(得分:-1)

快速解决方案: 您可以使用类似的方法来从PHP中使用explode()函数。以下是如何在C ++ enter link description here中创建爆炸函数的答案。可能您必须修改已回答的代码才能将standard C string作为输入。

然后,如果您将拥有自己的explode()函数版本,则可以执行std::vector<std::string> lines = explode(filedata,'\n')之类的操作。

下一步将为每个行元素做std::vector<std::string> line_elements = explode(lines[i], ';')。然后你将拥有每个单独的字段,你可以打印/解析你想要的东西。