I have a text file and I'm trying to right-align / justify the amounts (123.00 EUR
) to a specified column number (say 53
) by stretching the spaces before them appropriately
# 2018
; A comment
* Transactions
2018-01-01 @Payee | Internet
expenses:communication:internet 123.00 EUR
assets:cash:eur
2018-01-01 @Landlady | Rent
expenses:housing:rent 321.00 EUR
expenses:fees 2.50 EUR ; Bank fee
assets:bank:eur
The output should be
# 2018
; A comment
* Transactions
2018-01-01 @Payee | Internet
expenses:communication:internet 123.00 EUR
assets:cash:eur
2018-01-01 @Landlord | Rent
expenses:housing:rent 321.00 EUR
expenses:fees 2.50 EUR ; Bank fee
assets:bank:eur
It could probably be done with awk
or printf
or something but I can't figure it out.
More about the issue in the narrow sense as applied to hledger at Add option to print with normalized output width · Issue #1045 · simonmichael/hledger
CodePudding user response:
Using jq:
jq --raw-input --raw-output --argjson alignToColumn 53 '
"\\d \\.?\\d*\\s EUR" as $searchPattern | # regular expression to search for in each line
if test($searchPattern) # test if line contains "xxxxx.xx EUR"
then match($searchPattern) as $match | # match "xxxxx.xx EUR"
sub($searchPattern;
" " * ($alignToColumn - $match.offset - $match.length) # add leading spaces to matched "xxxxx.xx EUR"
$match.string)
else . # no match found in line
end
' file.txt
Remark
If a line contains more then one "xxxxx.xx EUR", the first match is aligned (see extra line "other stuff" in the output below)
Output
# 2018
; A comment
* Transactions
2018-01-01 @Payee | Internet
expenses:communication:internet 123.00 EUR
assets:cash:eur
2018-01-01 @Landlady | Rent
expenses:housing:rent 321.00 EUR
expenses:fees 2.50 EUR ; Bank fee
other stuff 7 EUR, 12.34 EUR
assets:bank:eur
CodePudding user response:
According to hledger's manual, the field separator seems to be two or more spaces.
You should be able to use it for picking up the lines that contain an account
and an amount
.
Here's an awk
idea for re-indenting the whole file with a given number of space characters while right-aligning the amounts:
awk -F ' {2,}|^ ' -v OFS=' ' '
FNR == NR {
if ( $1 !~ /^;/ ) {
if ( NF >= 2 && $2 !~ /^;/ ) {
account_size[FNR] = length($2)
if ( max_account_size < account_size[FNR] )
max_account_size = account_size[FNR]
if ( NF >= 3 && $3 !~ /^;/ ) {
amount_size[FNR] = length($3)
if ( max_amount_size < amount_size[FNR] )
max_amount_size = amount_size[FNR]
}
}
}
next
}
FNR in account_size {
$2 = (FNR in amount_size) ? sprintf("%-" max_account_size (max_amount_size - amount_size[FNR]) "s", $2) : $2
}
1
' file.txt file.txt
note: it's a two-pass algorithm so you need to provide the file twice
# 2018
; A comment
* Transactions
2018-01-01 @Payee | Internet
expenses:communication:internet 123.00 EUR
assets:cash:eur
2018-01-01 @Landlady | Rent
expenses:housing:rent 321.00 EUR
expenses:fees 2.50 EUR ; Bank fee
assets:bank:eur
remark: as you can see, the ; Bank fee
comment was also indented with OFS
CodePudding user response:
Using GNU awk for the 3rd arg to match:
$ cat tst.awk
match($0,/^([[:space:]] [^[:space:]] )[[:space:]] ([0-9.] [[:upper:]] )(.*)/,a) {
$0 = sprintf("%-39s s%s", a[1], a[2], a[3])
}
{ print }
$ awk -f tst.awk file
# 2018
; A comment
* Transactions
2018-01-01 @Payee | Internet
expenses:communication:internet 123.00 EUR
assets:cash:eur
2018-01-01 @Landlady | Rent
expenses:housing:rent 321.00 EUR
expenses:fees 2.50 EUR ; Bank fee
assets:bank:eur