0

Often I have code that I want to align based on similar structure of lines, not just the left-side auto indent. Is there a script out there that can do something like this? Here is an example of what I want to do. Given:

            self.colorOfBackground =? colorOfBackground
            self.colorOfLineForTime =? colorOfLineForTime
            self.marginOnBottom =? marginOnBottom
            self.marginOnTop =? marginOnTop
            ...

I want to run a script and align each "column" on a tab so that they are aligned and easier to visually parse:

            self.colorOfBackground     =?    colorOfBackground
            self.colorOfLineForTime    =?    colorOfLineForTime
            self.marginOnBottom        =?    marginOnBottom
            self.marginOnTop           =?    marginOnTop
            ...

I am thinking that a Perl or Python or AWK or some other scripting language could do this, but alas I know none of these. Till now I have been using Vim and its regex based substitution capabilities but I still spend most of the time manually spacing out the columns.

9
  • 1
    Does each column actually begin with a tab or several whitespace characters or is that just the way that you have it formatted here? Also, are there always three columns? Nov 28, 2020 at 4:31
  • Emacs has align-regexp. Are you looking for the column program?
    – icarus
    Nov 28, 2020 at 4:51
  • if you used a program to add some directives in the raw text, you could probably get tbl and nroff to format things how you like in monospaced ASCII, Been a while since I used them, so I can't make a detailed answer
    – infixed
    Nov 28, 2020 at 5:15
  • @NasirRiley The column may be tab-aligned (with tab character) or space character, it doesn't matter to me as long as they look aligned -- I think though using a space would be the preferred solution as it is tab-length independent. There could be more than 3 columns, but this is the typical scenario. The idea is to have these similar parts of a line aligned vertically.
    – andrewz
    Nov 28, 2020 at 7:12
  • Do you have any quoted strings (e.g. "foo bar") or comments or anything else in your input file that might contain blanks that you do not want to be considered "column" separators?
    – Ed Morton
    Nov 28, 2020 at 17:24

3 Answers 3

2

This will give you the expected result

File.txt :

self.colorOfBackground =? colorOfBackground
self.colorOfLineForTime =? colorOfLineForTime
self.marginOnBottom =? marginOnBottom
self.marginOnTop =? marginOnTop

When below command is used :

sed 's/^[[:blank:]]*//' File.txt | column -t -s "  "

This command will remove frontend spaces : sed 's/^[[:blank:]]*//' refer this stack overflow Question , explained in detail with an example what actually the command does stack overflow : click_here

Syntax : column -t [-s separator] [filename] -> column -t -s " "

–t : parameter to display the content in tabular format

-s : To separate the content based on a specific delimiter

Output of command :

self.colorOfBackground   =?  colorOfBackground
self.colorOfLineForTime  =?  colorOfLineForTime
self.marginOnBottom      =?  marginOnBottom
self.marginOnTop         =?  marginOnTop

Make sure before you make use of above command just align your entire data in file to left side in order to align data i have used : sed 's/^[[:blank:]]*//'

3
  • I noticed that the -s " " character gets eaten if I specify something else, ex. -s ":" for lines that look like this "parameter: type" results in "parameter type". Is there a way not to eat that character? I was expecting "parameter : type".
    – andrewz
    Nov 28, 2020 at 7:21
  • @andrewz yes i agree with you what you said but the user as provided the input content like that with spaces ,if the input data was separated by : then yours's one will work like charm for that Nov 28, 2020 at 9:44
  • I edited your answer because you don't need to pipe cat into sed. sed can be run directly against the file. Nov 28, 2020 at 12:59
2

Even though you've already accepted an answer, the result that you want can obtained with just one awk or sed command without having to pipe it into the column command.

awk '{print $1"\t\t"$2"\t\t"$3}' column.txt

sed -e 's/^[[:blank:]]*//' -e 's|\s|\t\t|g' column.txt

The sed command first removes all blank space at the beginning of each line and then converts any remaining spaces into two tabs. It gives this output:

self.colorOfBackground          =?              colorOfBackground
self.colorOfLineForTime         =?              colorOfLineForTime
self.marginOnBottom             =?              marginOnBottom
self.marginOnTop                =?              marginOnTop

The awk command prints just the first column which are the strings beginning with self and then prints two tabs, the second column which is =?, another two tabs, and finally, the string in the third column.

self.colorOfBackground          =?      colorOfBackground
self.colorOfLineForTime         =?      colorOfLineForTime
self.marginOnBottom             =?      marginOnBottom
self.marginOnTop                =?      marginOnTop

To edit the file itself instead of sending it to standard output, use either of the following:

sed -i -e 's/^[[:blank:]]*//' -e 's|\s|\t\t|g' column.txt 

awk -i inplace '{print $1"\t\t"$2"\t\t"$3}' column.txt

The awk command requires version 4.2 or later to have the -i inplace switch.

2
  • Awesome bro i like your logic of awk , can you tell what is the meaning of inplace Nov 28, 2020 at 13:52
  • It is for editing the file inplace. The -i switch for sed is the same. I edited the awk command a little to have it give the exact same output as the sed command. Nov 28, 2020 at 14:33
2

All you need is:

$ column -t file
self.colorOfBackground   =?  colorOfBackground
self.colorOfLineForTime  =?  colorOfLineForTime
self.marginOnBottom      =?  marginOnBottom
self.marginOnTop         =?  marginOnTop

or if you prefer:

$ column -t -o'    ' file
self.colorOfBackground     =?    colorOfBackground
self.colorOfLineForTime    =?    colorOfLineForTime
self.marginOnBottom        =?    marginOnBottom
self.marginOnTop           =?    marginOnTop

$ column -t -o$'\t' file
self.colorOfBackground  =?      colorOfBackground
self.colorOfLineForTime =?      colorOfLineForTime
self.marginOnBottom     =?      marginOnBottom
self.marginOnTop        =?      marginOnTop

$ column -t -o$'\t\t' file
self.colorOfBackground          =?              colorOfBackground
self.colorOfLineForTime         =?              colorOfLineForTime
self.marginOnBottom             =?              marginOnBottom
self.marginOnTop                =?              marginOnTop

Massage the column arguments to suit.

3
  • 1
    This is the simplest solution I've seen here. Very nice.
    – andrewz
    Nov 29, 2020 at 1:30
  • This is actually the better answer because it aligns into columns the entire line, which is more generic and applicable to other cases. Unfortunately I didn't phrase the question that way as I didn't expect such a complex problem to be solvable in such an easy way. Xcode should have a formatting feature like this, to simply invoke 'column -t' over selected lines; this would save me from copy/pasting into a unix terminal and running the command.
    – andrewz
    Dec 3, 2020 at 17:24
  • Even in vi you can define macros to call a command on a selected set of lines and replace that set of lines with the result so it'd be shocking if Xcode didn't also have that. You might want to search the archives for xcode questions and then post one tagged with xcode if you can't find an existing answer.
    – Ed Morton
    Dec 3, 2020 at 18:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.