在文件中搜索字符串(逐行),忽略单词之间的空白间隔的大小

时间:2011-12-22 02:07:09

标签: c++ string file-io

我是C ++的初学者,所以请理解......

我想通过分别读取每一行,然后在该行中搜索针来搜索文件(haystack)中的字符串(针)。然而,理想情况下,对于更健壮的代码,我希望能够只读取该行上的单个单词,这样如果在单词之间存在较大(即多个)的空白间隙,则在搜索针时会忽略它们。 (例如,可能使用>>运算符??)也就是说,针字符串不必与文件中单词之间的空格大小完全匹配。

所以,例如,如果我有针:

"The quick brown fox jumps over the lazy dog" 
文件中的

可能会写在(在特定行上):

... "The quick brown      fox jumps over the        lazy dog" ...

有一种有效的方法吗?

目前我在针线中包含了必要数量的空格,但如果可能的话,我想改进代码。

我的代码目前看起来类似于以下内容(在类中的方法中):

double var1, var2;
char skip[5];
std::fstream haystack ("filename");
std::string needle = "This is a string, and var1    =";
std::string line;
int pos;
bool found = false;

// Search for needle
while ( !found && getline (haystack,line) ) {
  pos = line.find(needle);  // find position of needle in current line

  if (pos != std::string::npos) { // current line contains needle

      std::stringstream lineStream(line);
      lineStream.seekg (pos + needle.length());
      lineStream >> var1;
      lineStream >> skip;
      lineStream >> var2;
      found = true;
  }
}

(为了清楚起见,在找到字符串(针)之后,我想在该行上存储下一个单词,或者在某些情况下存储下一个单词,然后跳过一个单词并存储下一个单词,例如:

使用文件:

... ...
... This is a string, and var1    = 111 and 777 ...
... ...

我想提取var1 = 111; var2 = 777;

提前感谢您的帮助!

3 个答案:

答案 0 :(得分:1)

您可以在line字符串中找到所有空格字符序列,并将其替换为单个空格。通过这种方式,您也可以替换needle中的多个空格,其余的搜索算法将继续保持不变。

以下是使用STL删除重复项的方法:

#include <iostream>
#include <algorithm>
#include <string>
#include <iterator>
using namespace std;

struct DupSpaceDetector {
    bool wasSpace;
    DupSpaceDetector() : wasSpace(0) {}
    bool operator()(int c) {
        if (c == ' ') {
            if (wasSpace) {
                return 1;
            } else {
                wasSpace = 1;
                return 0;
            }
        } else {
            wasSpace = 0;
            return 0;
        }
    }
};

int main() {
    string source("The quick brown      fox jumps over the        lazy dog");
    string destination;
    DupSpaceDetector detector;
    remove_copy_if(
        source.begin()
    ,   source.end()
    ,   back_inserter(destination)
    ,   detector
    );
    cerr << destination << endl;
    return 0;
}

答案 1 :(得分:1)

虽然我认为有一个更短的解决方案,但这将有效:

std::size_t myfind(std::string ins, std::string str) {
  for(std::string::iterator it = ins.begin(), mi = str.begin(); it != ins.end(); ++it) {
    if(*it == *mi) {
      ++mi;
      if (mi == str.end())
        return std::distance(ins.begin(),it);
    }
    else {
      if(*it == ' ')
        continue;
      mi = str.begin();
    }
  }
  return std::string::npos;
}
// use:
myfind("foo The quick brown      fox jumps over the        lazy dog bar", "The quick brown fox");

答案 2 :(得分:0)

要解决您的问题,您应该从针头和干草堆线上剥去多余的空间。 std::unique被定义为执行此操作。通常在对范围进行排序后使用它,但在这种情况下,我们真正想要做的就是删除重复的空格。

struct dup_space
{
   bool operator()( char lhs, char rhs )
   {
      return std::isspace( lhs ) && std::isspace( rhs );
   }
};

void despacer( const std::string& in, std::string& out )
{
   out.reserve( in.size() );
   std::unique_copy( in.begin(), in.end(),
         std::back_insert_iterator( out ),
         dup_space()
      );
}

您应该像这样使用它:

void find( const std::string& needle, std::istream haystack )
{
   std::string real_needle;
   despacer( needle, real_needle );

   std::string line;
   std::string real_line;
   while( haystack.good() )
   {
      line.clear();
      std::getline( haystack, line );

      real_line.clear();
      despacer( line, real_line );

      auto ret = real_line.find( real_needle );

      if( ret != std::string::npos )
      {
         // found it
         // do something creative
      }
   }
}