解析示例文本文件并将其拆分

时间:2012-09-16 20:38:50

标签: c++ string parsing

我正在尝试通过一个包含汇编指令的简单文本文件,它看起来像这样

TOP   NOP
VAL   INT 0
TAN   LA 2,1

这只是一个小例子,所以我可以告诉你它是如何工作的。基本上我将第一个标签放在标签上,然后是第二个标签,它们是NOP,INT和LA,并将它们放在操作码中。

之后我拿第一个参数(0和2)并将它们放在arg1中。然而,这就是我的问题所在。使用当前的代码,我将参数放入字符串时得到的输出是这样的

TOP
0
2

显然我只想让最后两个成为唯一的但是我怎么做才能让我的第一个参数不会抛出TOP?

#include <string>
#include <iostream>
#include <cstdlib>
#include <string.h>
#include <fstream>
#include <stdio.h>

using namespace std;

int main(int argc, char *argv[])
{
// If no extra file is provided then exit the program with error message
if (argc <= 1)
{
    cout << "Correct Usage: " << argv[0] << " <Filename>" << endl;
    exit (1);
}

// Array to hold the registers and initialize them all to zero
int registers [] = {0,0,0,0,0,0,0,0};

string memory [16000];

string Symtablelab[1000];
int Symtablepos[1000];

string line;
string label;
string opcode;
string arg1;
string arg2;

// Open the file that was input on the command line
ifstream myFile;
myFile.open(argv[1]);

if (!myFile.is_open())
{
    cerr << "Cannot open the file." << endl;
}

int counter = 0;
int i = 0;
int j = 0;

while (getline(myFile, line, '\n'))
{
    if (line[0] == '#')
    {
        continue;
    }

    if (line.length() == 0)
    {
        continue;
    }

    if (line[0] != '\t' && line[0] != ' ')
    {
        string delimeters = "\t ";

        int current;
        int next = -1;

        current = next + 1;
        next = line.find_first_of( delimeters, current);
        label = line.substr( current, next - current );

        Symtablelab[i] = label;

        current = next + 1;
        next = line.find_first_of(delimeters, current);
        opcode = line.substr(current, next - current);

        if (opcode != "WORDS" && opcode != "INT")
        {
            counter += 3;
        }

        if (opcode == "INT")
        {
            counter++;
        }

        delimeters = ", \n\t";
        current = next + 1;
        next = line.find_first_of(delimeters, current);
        arg1 = line.substr(current, next-current);

        cout << arg1<<endl;

        i++;
    }
}

2 个答案:

答案 0 :(得分:2)

使用这种技术有很多弱点,你根本不会检查任何结果。 例如,当你说:

current = next + 1;

您应该已经知道项目之间只有一个分隔符!否则你应该通过所有项目,当你说

next = line.find_first_of(delimeters, current);
<something> = line.substr(current, next - current)

您应该确定find_first_of找到了某些内容,否则它会返回-1而next - current会出现负面消息!

如果我想完成这项工作,我会使用regexstd使用boost并使用正则表达式执行这项任务是件小事,只需使用:

std::matches m;
std::regex rx("\\s*(\\w+)\\s+(\\w+)(?:\\s+(\\d+)\\s*(?:,(\\d+))?)?");
if (std::regex_match(line, m, rx)) {
    // we found a match here
    string label = m.str(1);
    string opcode = m.str(2);
    string arg1 = m.str(3), arg2 = m.str(4)
}

答案 1 :(得分:1)

问题在于寻找每个后续单词的开头:current = next + 1。你想要找到第一个非分隔符作为单词的开头,并在查找参数之前检查你是否在行的末尾。

添加调试信息,我看到以下内容:

>> label: start=0 end=3 value="TOP"
>> opcode: start=4 end=4 value=""

>> label: start=0 end=3 value="VAL"
>> opcode: start=4 end=4 value=""

>> label: start=0 end=3 value="TAN"
>> opcode: start=4 end=4 value=""

这告诉我每次操作opcode都会找到另一个分隔符。

问题是你只在单词之后递增一个而下一行line.substr()捕获分隔符。

在开始后的查找中,更改:

current = next + 1;

为:

current = line.find_first_not_of(delimeters, next + 1);

这允许它在任何和所有分隔符之后查找下一个单词的开头。

此外,您希望以持续的行长度为条件查找参数,因此将其包装在if(next >0) { ... }中。

这给了我调试和原始输出(有条件):

>> label: start=0 end=3 value="TOP"
>> opcode: start=6 end=-1 value="NOP"
>> label: start=0 end=3 value="VAL"
>> opcode: start=6 end=9 value="INT"
>> arg1: start=10 end=-1 value="0"
0
>> label: start=0 end=3 value="TAN"
>> opcode: start=6 end=8 value="LA"
>> arg1: start=9 end=10 value="2"
2

从主循环中重新分析您的解析/标记,以便您可以专注于它们。您甚至可能希望获得cppunit(或类似)来帮助您测试解析功能。如果没有这样,它可以帮助您到一个地方并插入调试信息,如:

cout << ">> " << whatIsBeingDebugged << ": " << start=" << current 
     << " end=" << next << " value= \"" << value << "\"" << endl;

制作一个强大的词法分析器和解析器是许多库(lex和yacc,flex和bison等)的主题,可以是其他应用程序,如正则表达式,甚至是整个大学课程。这是工作。但是,只需要有条不紊,彻底和单独测试,例如使用cppunit(或类似)进行单元测试。