Я получаю такое заявление в текстовом формате каждый месяц. Я не могу легко импортировать его в электронную таблицу.
28/03/2023 NETBANKING TRANSFER (Ref# 328012838897) 7,465.00 Cr
29/03/2023 BHAVNA CHEMIST 848.00
29/03/2023 ANUPAM STATIONERY MUMBAI 199.00
04/04/2023 SpayBBPS 2100001818 Mahan 30933624 1,134.00
Первый столбец — дата, последний (в некоторых случаях предпоследний) столбец — сумма. Средняя часть "описание"
28/03/2023 | NETBANKING TRANSFER (Ref# 328012838897) | 7,465.00 | Cr
29/03/2023 | BHAVNA CHEMIST | 848.00 |
29/03/2023 | ANUPAM STATIONERY MUMBAI | 199.00 |
04/04/2023 | SpayBBPS 2100001818 Mahan 30933624 | 1,134.00 |
Есть ли способ экспортировать его в csv?
Я попробовал эту команду:
awk '{print $1 " | some magic | " $NF}' test.txt
Как заменить «какую-то магию» на настоящий код? Я в порядке, если в последнем столбце появляется «Cr», я могу изменить это вручную.
Я могу получить второй столбец, используя cut следующим образом...
cat test.txt | cut -d ' ' -f2- | rev | cut -d ' ' -f2- | rev
Но я не уверен, как отформатировать его с первым и последним столбцом.
Использование sed
$ sed -E 's~[0-9/]+~& |~;s~([0-9]+,)?[0-9]+\.[0-9]+~| & |~' input_file
28/03/2023 | NETBANKING TRANSFER (Ref# 328012838897) | 7,465.00 | Cr
29/03/2023 | BHAVNA CHEMIST | 848.00 |
29/03/2023 | ANUPAM STATIONERY MUMBAI | 199.00 |
04/04/2023 | SpayBBPS 2100001818 Mahan 30933624 | 1,134.00 |
Некоторое объяснение этой магии будет оценено по достоинству.
Я бы использовал GNU AWK
для этой задачи следующим образом, пусть file.txt
контент будет
28/03/2023 NETBANKING TRANSFER (Ref# 328012838897) 7,465.00 Cr
29/03/2023 BHAVNA CHEMIST 848.00
29/03/2023 ANUPAM STATIONERY MUMBAI 199.00
04/04/2023 SpayBBPS 2100001818 Mahan 30933624 1,134.00
затем
awk '{$1=$1 " |";if ($NF+0){$NF = "| " $NF}else{$(NF-1) = "| " $(NF-1)};print}' file.txt
дает вывод
28/03/2023 | NETBANKING TRANSFER (Ref# 328012838897) | 7,465.00 Cr
29/03/2023 | BHAVNA CHEMIST | 848.00
29/03/2023 | ANUPAM STATIONERY MUMBAI | 199.00
04/04/2023 | SpayBBPS 2100001818 Mahan 30933624 | 1,134.00
Объяснение: я добавляю пробел, за которым следует символ вертикальной черты, к первому полю, чтобы отделить 1-е поле от остальных, затем я проверяю, имеет ли последний файл префикс, который представляет собой ненулевое число, если он сохраняется, я добавляю трубку, за которой следует пробел, к последнему полю, в противном случае я добавляю что поле перед последним. Отказ от ответственности Я предполагаю, что ваши входные данные всегда имеют 3 или более полей, если это не так, не используйте мой код.
(проверено в GNU Awk 5.0.1)
Ваша первая строка должна отделять Cr
как четвертое поле, а остальные имеют пустое поле, не так ли?
Все, что связано с PCRE, разрешает этот анализ.
Регулярное выражение:
/^(\d\d/\d\d/\d\d\d\d)\s+(.*?)\s+([\d,]+\.\d\d) *(.*)$/
Разделяет четыре группы. Демо
Вот Ruby, использующий это регулярное выражение:
ruby -e '$<.each{|line|
puts line.scan(/^(\d\d/\d\d/\d\d\d\d)\s+(.*?)\s+([\d,]+\.\d\d) *(.*)$/).join(" | ") }
' file
Или Перл:
perl -nE 'say join(" | ", $1, $2, $3, $4)
if m/^(\d\d/\d\d/\d\d\d\d)\s+(.*?)\s+([\d,]+\.\d\d) *(.*)$/' file
Вы также можете сделать это в два этапа с помощью sed
, если версия поддерживает {repetitions}
, что делают большинство современных версий:
sed -E 's/^[0-9]{2}/[0-9]{2}/[0-9]{4} /&| /; s/(.*) ([0-9,]{1,}\.[0-9]{2})(.*)$/\1 | \2 | \3/' file
Любой из этих принтов:
28/03/2023 | NETBANKING TRANSFER (Ref# 328012838897) | 7,465.00 | Cr
29/03/2023 | BHAVNA CHEMIST | 848.00 |
29/03/2023 | ANUPAM STATIONERY MUMBAI | 199.00 |
04/04/2023 | SpayBBPS 2100001818 Mahan 30933624 | 1,134.00 |
Это может сработать для вас (GNU sed):
sed -E 's/( .*)( [0-9,.]+) ?/ |\1 |\2 | /' file
Используя жадность: поместите 3 разделителя |
(с пробелами по обеим сторонам), заменив первый пробел, тот, что перед последним числом, и после последнего числа.
элегантно и читабельно. Проголосовал и принял.
Я получаю те же результаты, если удаляю пробел и вопросительный знак '?' Это нормально или это необходимо?
@shantanuo просто belt n'braces
на случай, если число будет самым последним полем в строке.
Предположения:
|
(в отличие от примера вывода OP, который варьируется от 1 до 2 пробелов)Cr
в примере), это 4-е поле никогда не содержит числа|
(без пробела в конце)Одна awk
идея:
awk '
{ $1=$1 " |" # append " |" to 1st field
if ($NF ~ /[0-9]/) # if last field is a monetary value (ie, no 4th field)
$NF = "| " $NF " |" # prepend with "| " and end line with "|" (sans trailing white space)
else { # else prepend last two fields with "| "
$(NF-1) = "| " $(NF-1)
$NF = "| " $NF
}
}
1 # print modified line to stdout
' test.txt
Это генерирует:
28/03/2023 | NETBANKING TRANSFER (Ref# 328012838897) | 7,465.00 | Cr
29/03/2023 | BHAVNA CHEMIST | 848.00 |
29/03/2023 | ANUPAM STATIONERY MUMBAI | 199.00 |
04/04/2023 | SpayBBPS 2100001818 Mahan 30933624 | 1,134.00 |
Предполагая, что вам действительно нужен действительный вывод CSV, используйте GNU awk в качестве третьего аргумента для match()
:
$ cat tst.awk
BEGIN { OFS = "\",\"" }
match($0,/^(\S+)\s+(.*\S)\s+([0-9][0-9,.]*)\s*(\S+)?$/,a) {
print "\"" a[1], a[2], a[3], a[4] "\""
}
$ awk -f tst.awk file
"28/03/2023","NETBANKING TRANSFER (Ref# 328012838897)","7,465.00","Cr"
"29/03/2023","BHAVNA CHEMIST","848.00",""
"29/03/2023","ANUPAM STATIONERY MUMBAI","199.00",""
"04/04/2023","SpayBBPS 2100001818 Mahan 30933624","1,134.00",""
Если ваши строки ввода могут содержать двойные кавычки, добавьте их непосредственно перед строкой print
, чтобы избежать их в выводе:
for ( i=1; i in a; i++ ) {
gsub(/"/,"\"\"",a[i])
}
С разделителем из трех символов
' | '
у вас действительно нет CSV-файла.