通过正则表达式解析 C++ 多数据文本 [已关闭]

C++ multi data text parse via regex [closed]

提问人:hdcdigi 提问时间:4/7/2023 更新时间:4/7/2023 访问量:55

问:


想改进这个问题吗?更新问题,以便可以通过编辑这篇文章用事实和引文来回答。

8个月前关闭。

要解析的文本:

001  B001C001_230130_RQ7V V     C        04:23:30:18 04:24:14:01 01:00:00:00 01:00:43:08  
*ASC_SOP (1.000000 1.000000 1.000000)(0.000000 0.000000 0.000000)(1.000000 1.000000 1.000000)
*ASC_SAT 1.000000

我正在尝试将 *ASC_SOP 个三元组解析为 3x float[3] 数组。

源文件被加载并逐行传递给函数。当前函数如下所示:parse()

inline void parse(std::string &line) {

    //regex to match edl id's camera reel and slope values
    std::regex edlID("^([0-9]{3})");
    std::regex camReel("([A-Za-z]([0-9]{3}))\\S+");
    std::regex SOP("(?:[0-9][.][0-9]{6})");

    std::smatch mID, reelID, sopMatch; //regex matchers

    //check if there is an edlID. As per CM3600 spec this is always the first column
    if(std::regex_search(line, mID, edlID)) {
        std::regex_search(line, reelID, camReel); //next we check for a clip/reel name combo
        std::cout << "EDL ID: " << mID[0] << " Clip: " << reelID[0] << std::endl;
    }
}

将 *ASC_SOP 值和 ASC_SAT 值解析为相应浮点数的最佳方法是什么?正则表达式是最好的解决方案吗?还是基于令牌的字符串流更好?我的一个想法是去掉所有括号的行,然后用分隔符再次迭代。有没有人有一种有效的方法来处理这个问题?' '

C++ 正则表达式 stringstream

评论

0赞 Pepijn Kramer 4/7/2023
使用正则表达式解析为字符串,然后使用 std::stof(或 std::stod)转换为浮点数(注意,一个好方法是先在这里开发/删除您的正则表达式: regex101.com)

答:

0赞 Jerry Coffin 4/7/2023 #1

假设您在这里关心的行始终遵循相同的基本模式:后跟三组 parens,每组包含三个浮点数,我可能会使用 .对于这样的情况,我通常从一个小的固定模式匹配器1 开始:*ASC_SOPstringstream

std::istream &operator>>(std::istream &is, char const *pat) {
    while (is.peek() == *pat) {
        ++pat;
        is.ignore(1);
    }
    if (*pat)
        is.setstate(std::ios::failbit);
    return is;
}

有了这个,我们可以做这样的事情:

    float a[3], b[3], c[3];

    if (input >> "*ASC_SOP (" >> a[0] >> a[1] >> a[2] >> ")(" 
                              >> b[0] >> b[1] >> b[2] >> ")(" 
                              >> c[0] >> c[1] >> c[2] >> ")") 
    {
        std::cout << "parsed ASC_SOP\n";
    } else {
        std::cerr << "Attempt at parsing ASC_SOP failed\n";
    }

尽管模式匹配器本身并不完全直观,但至少在我看来,它似乎使代码的其余部分变得非常清晰易懂(一旦你理解了它的意图,模式匹配器也不是特别困难)。


  1. 根据具体情况,可以更详细地进行一些操作,例如,如果设置了流标志,则让它将模式中的任何空格与输入流中的任意数量的空格进行匹配,就像在 form 字符串中发生的那样 for 和 company。如果(例如)在结束部分和下一个开始部分之间可能有也可能没有空格(或可能制表符),这可能很有用。但是,一旦你有了基本的想法,如果需要,添加这样的东西就很容易了。skipwsscanf

评论

0赞 hdcdigi 4/9/2023
这很好,谢谢。这背后的概念是否植根于操作员超载?这不是我熟悉的东西,所以需要研究它才能完全理解。我试图修改您的用法示例语句以说明该值,但它似乎不起作用。我尝试了以下方法,但它似乎没有返回值。我尝试使用标志并删除if语句中的空格。if*ASC_SATif(sourceline_stringstream >> "*ASC_SAT " >> targetFloat){...}skipws
0赞 Jerry Coffin 4/10/2023
是的,这是一个重载的运算符。
0赞 hdcdigi 4/10/2023
为什么我无法使用相同的方法获得 SAT 值?
0赞 Jerry Coffin 4/10/2023
@hdcdigi:不,至少在没有看到代码的情况下不会。两者之间没有太多明显的区别。