timonsku
timonsku

Reputation: 1259

Formatting text data with C++ or any windows scripting language

This may be a simple task but at the moment I really have no clue how I could do this in a simple way. I have the following situation, I have a script written in COFFEE, the scripting language of the 3D program Cinema 4D. Now this script is writing position data in the following format into a text file (rtf in that case but can be a .txt aswell).

0  0.0  471.2  0.0
1  0.0  470.5  0.0
2  0.0  468.8  0.0
3  0.0  465.9  0.0
4  0.0  461.9  0.0
5  0.0  456.8  0.0
6  0.0  450.5  0.0
7  0.0  443.2  0.0
8  0.0  434.8  0.0
9  0.0  425.2  0.0

Frame, X, Y, Z.

Now what I need to do is getting this position data into this format:

Transform   Position
    Frame   X pixels    Y pixels    Z pixels    
    0   0.0    471.2    0.0 
    1   0.0    470.5    0.0 
    2   0.0    468.8    0.0 


End of Keyframe Data

It is not really visible here but there are no spaces in here, everything is spaced with tab (maybe copy that to notepad to really see the tabs). It's important that I have tabs between every number, there can be spaces but I need exactly one tab character everytime. So the most important part is, how do I get those numbers from the first data set and bring and let the program add a \t between every number?

I tried to do this within the script but the script fails if I use a tab instead of several spaces between my positions. I searched quite a lot but couldn't find any good solution for this. I'm familiar with C++ and a little batch script but I'm happy for every solution even if I have to learn the basics of another language.

I tried to find a way in C++ but no way that I came up with could format an n number of lines and every single one was way to complicated. The number of frames/lines varies everytime so I never have a fixed line count.

Upvotes: 1

Views: 1765

Answers (3)

ely
ely

Reputation: 77424

An example Python script if interested.

#!c:/Python/python.exe -u
# Or point it at your desired Python path
# Or on Unix something like: !/usr/bin/python

# Function to reformat the data as requested.
def reformat_data(input_file, output_file):

    # Define the comment lines you'll write.
    header_str = "Transform\tPosition\n"
    column_str = "\tFrame\tX pixels\tY pixels\tZ pixels\n"
    closer_str = "End of Keyframe Data\n"

    # Open the file for reading and close after getting lines.
    try:
        infile = open(input_file)
    except IOError:
        print "Invalid input file name..."
        exit()

    lines = infile.readlines()
    infile.close()

    # Open the output for writing. Write data then close.
    try:
        outfile = open(output_file,'w')
    except IOError:
        print "Invalid output file name..."
        exit()

    outfile.write(header_str)
    outfile.write(column_str)

    # Reformat each line to be tab-separated.
    for line in lines:
        line_data = line.split()
        if not (len(line_data) == 4):
            # This skips bad data lines, modify behavior if skipping not desired.
            pass 
        else:
            outfile.write("\t".join(line_data)+"\n")

    outfile.write(closer_str)
    outfile.close()

#####
# This below gets executed if you call
# python <name_of_this_script>.py
# from the Powershell/Cygwin/other terminal.
#####
if __name__ == "__main__":
    reformat_data("/path/to/input.txt", "/path/to/output.txt")

Upvotes: 1

Retired Ninja
Retired Ninja

Reputation: 4924

Something like this might work. I didn't do any special formatting of the numbers, so if you need that you'll need to add it. If you're worried about a malformed input file, like not enough numbers on a line then you'd want to add some additional error checking to guard against it.

#include <fstream>
#include <iostream>
#include <vector>

bool Convert(const char* InputFilename, const char* OutputFilename)
{
    std::ifstream InFile(InputFilename);
    if(!InFile)
    {
        std::cout << "Could not open  input file '" << InputFilename << "'" << std::endl;
        return false;
    }

    struct PositionData
    {
        double FrameNum;
        double X;
        double Y;
        double Z;
    };
    typedef std::vector<PositionData> PositionVec;

    PositionVec Positions;
    PositionData Pos;
    while(InFile)
    {
        InFile >> Pos.FrameNum >> Pos.X >> Pos.Y >> Pos.Z;
        Positions.push_back(Pos);
    }

    std::ofstream OutFile(OutputFilename);
    if(!OutFile)
    {
        std::cout << "Could not open output file '" << OutputFilename << "'" << std::endl;
        return false;
    }

    OutFile << "Transform\tPosition\n\tFrame\tX pixels\tY pixels\tZ pixels" << std::endl;
    for(PositionVec::iterator it = Positions.begin(); it != Positions.end(); ++it)
    {
        const PositionData& p(*it);
        OutFile << "\t" << p.FrameNum << "\t" << p.X << "\t" << p.Y << "\t" << p.Z << std::endl;
    }
    OutFile << "End of Keyframe Data" << std::endl;
    return true;
}

int main(int argc, char* argv[])
{
    if(argc < 3)
    {
        std::cout << "Usage: convert <input filename> <output filename>" << std::endl;
        return 0;
    }
    bool Success = Convert(argv[1], argv[2]);

    return Success;
}

Upvotes: 2

marcinj
marcinj

Reputation: 49986

yet another example using regexps

#include <fstream>
#include <iostream>
#include <regex>
#include <algorithm>
int main()
{
    using namespace std;

    ifstream inf("TextFile1.txt");
    string data((istreambuf_iterator<char>(inf)), (istreambuf_iterator<char>()));

    regex reg("([\\d|\.]+)\\s+([\\d|\.]+)\\s+([\\d|\.]+)\\s+([\\d|\.]+)");  
    sregex_iterator beg(data.cbegin(), data.cend(), reg), end;

    cout << "Transform\tPosition" << endl;
    cout << "\tFrame\tX pixels\tY pixels\tZ pixels" << endl;
    for_each(beg, end, [](const smatch& m) {
        std::cout << "\t" << m.str(1) << "\t" << m.str(2) << "\t" << m.str(3) << "\t" << m.str(4) << std::endl;
    });
    cout << "End of Keyframe Data" << endl;
}

Upvotes: 2

Related Questions