我有一个文本文件,我正试图右对齐/调整数量(123.00 EUR
)到指定的列号(说53
)通过适当地拉伸它们之前的空格
# 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
输出应该是
# 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
可能是awk
或printf
之类的,但我想不出来。
关于狭义上的问题的更多信息,请参见添加选项以标准化输出宽度打印·issue #1045·simmonmichael/hledger
使用GNU awk来匹配第三个参数:
$ cat tst.awk
match($0,/^([[:space:]]+[^[:space:]]+)[[:space:]]+([0-9.]+ [[:upper:]]+)(.*)/,a) {
$0 = sprintf("%-39s %13s%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
我使用%-39s %13s
而不是上面的%-40s%13s
,以确保您在两个字段之间获得空格,即使第一个字段最终超过40个字符。
使用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
不使用"if-then-else":
更紧凑的版本jq --raw-input --raw-output --argjson alignToColumn 53 '
"\d+\.?\d*\s+EUR" as $searchPattern |
( match($searchPattern) as $m
| .[:$m.offset] + ($alignToColumn - $m.offset - $m.length) * " " + .[$m.offset:]
) // .
' file.txt
评论
如果一行包含多个"xxxxx。xx EUR",第一个匹配是对齐的(见额外的一行"其他东西")在下面的输出中)
输出# 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
根据hledger手册,字段分隔符为两个或多个空格.
同样,account
的行至少有2个(未注释)字段,amount
的行有3个(未注释)字段。
您可以使用这个事实来区分带有amount
的行与其他行。
这是一个awk
的想法,使用给定数量的空格重新缩进整个文件,同时右对齐数量;这和你问的有点不同因为你不需要指定要移动金额的列,它会根据最大帐户字符串对它们进行对齐:
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
<一口>注意:这是一个两遍算法所以你需要提供两次文件一口>
# 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
<一口>备注:如您所见,; Bank fee
注释被认为是一个字段,因此它被OFS
一口>