2

I have a list of C++ source files, which have the following structure:

// A lot of stuff
#include <current/parser/support/base.hpp>
// ...
#include <current/parser/iterators/begin.hpp>
// ...

I need to replace lines like

#include <current/parser/support/base.hpp>

with

#include <support_base.hpp>

Namely, omit the current/parser and replace the separator (/) with _. Is this possible to do with bash sed or a scripting language?

EDIT: Sorry, forgot to mention that I want to replace anything like

#include <current/parser/*/*/*/*>

Anything can go after current/parser, and with any depth.

4
  • 1
    sed could do it, but you should keep in mind that using those tool(sed/awk...) to "fix" your source codes could bring new problems. it's risky. Commented Jun 10, 2014 at 8:49
  • Do you want to replace just those lines containing current/parser or all the ones containing any #include <anypath/last/file.hpp>? Commented Jun 10, 2014 at 8:50
  • Edited. Anything that starts with #include <current/parser... Commented Jun 10, 2014 at 8:55
  • So given your current edited example, you want #include <*_*_*_*> as output? Commented Jun 10, 2014 at 8:58

4 Answers 4

3

Going with Tcl:

# Open the file for reading
set fin [open filein.c r]
# Open the file to write the output
set fout [open fileout.c w]

# Loop through each line
while {[gets $fin line] != -1} {
    # Check for lines beginning with "^#include <current/parser/"
    #
    # ^ matches the beginning of the line
    # ([^>]*) matches the part after "#include <current/parser/" and stores it
    #    in the variable 'match'

    if {[regexp {^#include <current/parser/([^>]*)>} $line - match]} {
        # the edited line is now built using the match from above after replacing
        #    forward slashes with underscores
        set newline "#include <[string map {/ _} $match]>"
    } else {
        set newline $line
    }
    # Put output to the file
    puts $fout $newline
}

# Close all channels
close $fin
close $fout

Output with the provided input:

// A lot of stuff
#include <support_base.hpp>
// ...
#include <iterators_begin.hpp>
// ...

Demo on codepad (I edited the code a bit since I can't have a channel open to read/write in files there)

Sign up to request clarification or add additional context in comments.

Comments

3

Using sed:

sed -i -e '/#include <current\/parser\/support\/base\.hpp>/{ s|current/parser/||; s|/|_|; }' -- file1 file2 file3

Edit:

sed -i -e '/#include <current\/parser\/.*>/{ s|current/parser/||; s|/|_|g; }' -- file1 file2 file3

Would remove currrent/parsers/ and replace all / with _. Example result file:

// A lot of stuff
#include <support_base.hpp>
// ...
#include <iterators_begin.hpp>
// ...

Some details:

/#include <current\/parser\/.*>/  --  Matcher.
s|current/parser/||               --  Deletes `current/parser/` in matched line.
s|/|_|g                           --  Replaces all `/` with `_` in same line.

1 Comment

Very nice approach, I specially like the {} block that handles all amount of /. Also, a small explanation would help people understand it better.
0

You can try it with sed and -r for regular expression:

sed -r 's|#include <current/parser/support/base\.hpp>|#include <support_base.hpp>|g' file

But using this way could kill your code. So be carefull :)

3 Comments

Errr but this is quite hardcoded, isn't it? What about iterators/begin.hpp?
Also, some more description as to how it can kill a code would be nice. By the way, . in regex matches almost any character. Is it different in sed?
Thanks for that hint @Jerry, forgot to escape it :)
0

Using a perl one-liner

perl -i -pe 's{^#include <\Kcurrent/parser/([^>]*)}{$1 =~ y|/|_|r}e;' file.cpp

Or without regex features greater than perl 5.10

perl -i -pe 's{(?<=^#include <)current/parser/([^>]*)}{join "_", split "/", $1}e;' file.cpp

Explanation:

Switches:

  • -i: Edit files in place (makes backup if extension supplied)
  • -p: Creates a while(<>){...; print} loop for each line in your input file.
  • -e: Tells perl to execute the code on command line.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.