mercredi 26 septembre 2018

How can I speed up parsing of large strings?

So I've made a program that reads in various config files. Some of these config files can be small, some can be semi-large (largest one is 3,844 KB).

The read in file is stored in a string (in the program below it's called sample).

I then have the program extract information from the string based on various formatting rules. This works well, the only issue is that when reading larger files it is very slow....

I was wondering if there was anything I could do to speed up the parsing or if there was an existing library that does what I need (extract string up until a delimiter & extract string string in between 2 delimiters on the same level). Any assistance would be great.

Here's my code & a sample of how it should work...

#include "stdafx.h"

#include <string>
#include <vector>

std::string ExtractStringUntilDelimiter(
   std::string& original_string,
   const std::string& delimiter,
   const int delimiters_to_skip = 1)
{
   std::string needle = "";

   if (original_string.find(delimiter) != std::string::npos)
   {
      int total_found = 0;

      auto occurance_index = static_cast<size_t>(-1);

      while (total_found != delimiters_to_skip)
      {
         occurance_index = original_string.find(delimiter);
         if (occurance_index != std::string::npos)
         {
            needle = original_string.substr(0, occurance_index);
            total_found++;
         }
         else
         {
            break;
         }
      }

      // Remove the found string from the original string...
      original_string.erase(0, occurance_index + 1);
   }
   else
   {
      needle = original_string;
      original_string.clear();
   }

   if (!needle.empty() && needle[0] == '\"')
   {
      needle = needle.substr(1);
   }
   if (!needle.empty() && needle[needle.length() - 1] == '\"')
   {
      needle.pop_back();
   }

   return needle;
}

void ExtractInitialDelimiter(
   std::string& original_string,
   const char delimiter)
{
   // Remove extra new line characters
   while (!original_string.empty() && original_string[0] == delimiter)
   {
      original_string.erase(0, 1);
   }
}

void ExtractInitialAndFinalDelimiters(
   std::string& original_string,
   const char delimiter)
{
   ExtractInitialDelimiter(original_string, delimiter);

   while (!original_string.empty() && original_string[original_string.size() - 1] == delimiter)
   {
      original_string.erase(original_string.size() - 1, 1);
   }
}

std::string ExtractStringBetweenDelimiters(
   std::string& original_string,
   const std::string& opening_delimiter,
   const std::string& closing_delimiter)
{
   const size_t first_delimiter = original_string.find(opening_delimiter);
   if (first_delimiter != std::string::npos)
   {
      int total_open = 1;
      const size_t opening_index = first_delimiter + opening_delimiter.size();

      for (size_t i = opening_index; i < original_string.size(); i++)
      {
         // Check if we have room for opening_delimiter...
         if (i + opening_delimiter.size() <= original_string.size())
         {
            for (size_t j = 0; j < opening_delimiter.size(); j++)
            {
               if (original_string[i + j] != opening_delimiter[j])
               {
                  break;
               }
               else if (j == opening_delimiter.size() - 1)
               {
                  total_open++;
               }
            }
         }


         // Check if we have room for closing_delimiter...
         if (i + closing_delimiter.size() <= original_string.size())
         {
            for (size_t j = 0; j < closing_delimiter.size(); j++)
            {
               if (original_string[i + j] != closing_delimiter[j])
               {
                  break;
               }
               else if (j == closing_delimiter.size() - 1)
               {
                  total_open--;
               }
            }
         }


         if (total_open == 0)
         {
            // Extract result, and return it...
            std::string needle = original_string.substr(opening_index, i - opening_index);
            original_string.erase(first_delimiter, i + closing_delimiter.size());

            // Remove new line symbols
            ExtractInitialAndFinalDelimiters(needle, '\n');
            ExtractInitialAndFinalDelimiters(original_string, '\n');

            return needle;
         }
      }
   }

   return "";
}

int main()
{
   std::string sample = "{\n"
      "Line1\n"
      "Line2\n"
      "{\n"
         "SubLine1\n"
         "SubLine2\n"
      "}\n"
   "}";

   std::string result = ExtractStringBetweenDelimiters(sample, "{", "}");
   std::string LineOne = ExtractStringUntilDelimiter(result, "\n");
   std::string LineTwo = ExtractStringUntilDelimiter(result, "\n");

   std::string SerializedVector = ExtractStringBetweenDelimiters(result, "{", "}");
   std::string SubLineOne = ExtractStringUntilDelimiter(SerializedVector, "\n");
   std::string SubLineTwo = ExtractStringUntilDelimiter(SerializedVector, "\n");

   // Just for testing...
   printf("LineOne: %s\n", LineOne.c_str());
   printf("LineTwo: %s\n", LineTwo.c_str());
   printf("\tSubLineOne: %s\n", SubLineOne.c_str());
   printf("\tSubLineTwo: %s\n", SubLineTwo.c_str());
   system("pause");
}

Aucun commentaire:

Enregistrer un commentaire