【问题标题】:Extracting x, y, z coordinates from string?从字符串中提取x,y,z坐标?
【发布时间】:2020-08-10 14:58:14
【问题描述】:

我有一个字符串向量,vector <string> shapes 保存这些坐标数据:

Shape1, [3, 2]
Shape1, [6, 7]
Shape2, [7, 12, 3], [-9, 13, 68]
Shape1, [10, 3]
Shape2, [30, -120, 3], [-29, 1, 268]
Shape3, [15, 32], [1, 5]
Shape4, [24, 31, 56]

我正在尝试从Shape1Shape3xyzShape2Shape4 中计算出坐标xy。这是一个可重现的代码:

#include <stdio.h>
#include <iostream>
#include <vector>
#include <string>

using namespace std;

int main()
{
    vector <string> shapes;
    
    shapes.push_back("Shape1, [3, 2]");
    shapes.push_back("Shape1, [632, 73]");
    shapes.push_back("Shape2, [7, 12, 3], [-9, 13, 68]");
    shapes.push_back("Shape1, [10, 3]");
    shapes.push_back("Shape2, [30, -120, 3], [-29, 1, 268]");
    shapes.push_back("Shape3, [15, 32], [1, 5]");
    shapes.push_back("Shape4, [24, 31, 56]");
    
    for(int i = 0; i < shapes.size(); i++)
    {
        // attempt to extract x
        size_t string_start = shapes[i].find(", [");
        string extracted = shapes[i].substr(string_start + 3, 1);
        
        cout << extracted << endl;
    }
    
    return 0;
}

就像现在一样,我当前的代码不能正确地cout x - 只有x 的第一个字符是cout。我应该如何处理x的长度?随后,我应该如何cout数据中的yz?分隔符是,,但到处都有多个,

【问题讨论】:

  • 您可以通过以更合理的方式存储数据来减轻痛苦。
  • 从你的 x 坐标,你可能想读到下一个,
  • @Amachi 关于我如何做到这一点的任何参考?
  • @user3118602 我摆弄了一下,为你的问题做了一个不完美的解决方案。你可能想推进它。

标签: c++ string vector substring


【解决方案1】:

由于您已经有了 x 坐标的起点,您可以使用该位置从那里开始寻找下一个“,”。 例如

size_t string_start = shapes[i].find(", [");
size_t x_end = shapes[i].find_first_of(',', string_start + 3);

std::string parsed_x = shapes[i].substr(string_start, x_end - (string_start + 3));

这不包括有一个 Shape2 的情况,它看起来有多个 x 位置。 但是对于这种情况,您可以创建一个函数来提取“x”坐标并让它多次通过您的行。

【讨论】:

    【解决方案2】:

    以下代码改编自this stack overflow answer,去那里获取完整解释。

    #include <stdio.h>
    #include <iostream>
    #include <vector>
    #include <string>
    #include <map>
    
    using namespace std;
    
    map<char, int> extract(string s) {
        map<char, int> r;
        size_t pos = 0;
        string token;
        char axes[] = {'x', 'y', 'z'};
        int count = 0;
        while ((pos = s.find(", ")) != string::npos) {
            token = s.substr(0, pos);
            r[axes[count++]] = stoi(token);
            s.erase(0, pos + 2); # ", ".length() == 2
        }
        r[axes[count]] = stoi(s);
        return r;
    }
    
    int main()
    {
        vector <string> shapes;
        
        shapes.push_back("Shape1, [3, 2]");
        shapes.push_back("Shape1, [632, 73]");
        shapes.push_back("Shape2, [7, 12, 3], [-9, 13, 68]");
        shapes.push_back("Shape1, [10, 3]");
        shapes.push_back("Shape2, [30, -120, 3], [-29, 1, 268]");
        shapes.push_back("Shape3, [15, 32], [1, 5]");
        shapes.push_back("Shape4, [24, 31, 56]");
    
        
        size_t pos = 0;
        string token;
        for(int i = 0; i < shapes.size(); i++) {
            string s = shapes[i];
            while ((pos = s.find(", [")) != string::npos) {
                auto r = extract(s.substr(pos + 3, s.find("]") - (pos + 3)));  # ", [".length() == 3
                cout << "X: " << r['x'] << ", Y: " << r['y'] << (r.count('z') ? ", Z: " + to_string(r['z']) : "") << endl;
                s.erase(0, pos + 3); # ", [".length() == 3
            }
        }
        
        return 0;
    }
    

    进一步改进

    可以通过将提取的值存储在Shape 类或某种结构中来增强上述代码。这样,您必须执行一次此操作,并根据需要多次处理数据。但是,如果您的唯一目标是打印数据,那么上面的代码就足够了。

    【讨论】:

      【解决方案3】:

      我认为更简单的另一种方法是使用正则表达式模式匹配和搜索。我认为这将更适合处理变量坐标数据并更容易处理字符串。 std::regex_token_iterator 可以做你需要的。它是(根据 cppreference):

      访问个人的只读 LegacyForwardIterator 正则表达式的每个匹配项的子匹配项 底层字符序列。它也可以用于访问零件 与给定正则表达式不匹配的序列 (例如,作为分词器)。

      首先,您可以使用正则表达式来获取每个形状字符串中的坐标。以下正则表达式将匹配以[ 开头并以] 结尾的序列,捕获这些字符中的文本:

      std::regex reg(R"(\[(.+?)\])");
      

      然后使用提取的字符串,我们可以将字符串标记为单独的坐标。现在我们为分隔符", " 使用正则表达式,并将-1 作为第四个参数传递给std::sregex_token_iterator 以获取它们之间的文本。

      我认为这个功能可以满足您的需要:

      #include <iostream>
      #include <regex>
      #include <string>
      #include <map>
      #include <vector>
      
      namespace
      {
          std::map<int, std::string> lookup = { {0, "x"}, {1, "y"}, {2, "z"} };
      }
      
      void PrintShape(const std::string &shape)
      {
          std::regex reg(R"(\[(.+?)\])");
          std::smatch mr;
          std::regex_search(shape, mr, reg);
      
          size_t string_start = shape.find(",");
          std::cout << shape.substr(0, string_start) << ":" << "\t";
      
          auto start = std::sregex_iterator(shape.begin(), shape.end(), reg);
          auto end = std::sregex_iterator{};
      
          for (std::sregex_iterator it = start; it != end; ++it)
          {
              //Get the first capturing group: [x, y, z]
              auto str = (*it)[1].str();
      
              //Tokenize group into x,y,z coordinates using delimiter ", "
              std::regex rgx(R"(, )");
              std::sregex_token_iterator iter(str.begin(), str.end(), rgx, -1);
              std::sregex_token_iterator iter_end{};
      
              //Print the coordinates
              int i = 0;
              std::cout << "[";
              for (; iter != iter_end; ++iter)
              {
                  std::cout << lookup[i++] << " = " << *iter;
      
                  if (std::next(iter) != iter_end)
                  {
                      std::cout << ", ";
                  }
              }
              std::cout << "] ";
          }
          std::cout << "\n";
      }
      

      这是demo

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-04-10
        • 1970-01-01
        • 2021-03-30
        • 1970-01-01
        • 2014-05-18
        • 1970-01-01
        相关资源
        最近更新 更多