Обновлен для уточнения того, что обратные галочки, которые уже присутствуют, должны быть удвоены
Один из способов - split
на |
и обрезать заключающие в кавычки, чтобы сделать оставшиесярегулярное выражение, затем соберите строку обратно.Это может потерять некоторую эффективность по сравнению с одним регулярным выражением, но гораздо проще поддерживать
perl -F"\|" -wlanE'
say join "\|",
map { s/^"|"$//g; s/`/``/g; s/"([^"]+)"/`$1`/g; qq("$_") } @F
' data.txt
Опция -a
делает его "автоматически разбитым" на каждую строку, поэтому в программе токены строк доступны в @F
, а -F
указывает шаблон для разделения (кроме значения по умолчанию).-l
обрабатывает переводы строк.См. Командные переключатели в perlrun .
В map
включающие "
s удалены, а любые существующие обратные помехи удвоены;затем "
вокруг шаблонов меняются глобально.Затем кавычки возвращаются и возвращаемый список join
-ed.|
в join
экранируется, чтобы пропустить его через оболочку в программу Perl;если это входит в сценарий (вместо однострочного), что я всегда рекомендую, замените это \|
на |
.
Я не знаю типичные данные и возможные крайние случаиотносительно цитат, но если могут быть свободные (одиночные, непарные) цитаты, вышеупомянутые будут иметь проблемы и могут привести к неправильному выводу, и тихо;как любая процедура, которая ожидает парные кавычки, без чрезвычайно подробного анализа.
В целом безопаснее просто заменить все "
(кроме включенных) на
map { s/^"|"$//g; s/`/``/g; s/"/`/g; qq("$_") }
(или tr
вместо регулярного выражения s///g
).Это также добавляет некоторую меру эффективности.
Еще один способ добраться до «мяса» данных - использовать Text :: CSV , который позволяет использовать разделитель, отличный от (по умолчанию) и поглощает кавычки.Наличие кавычек внутри полей считается плохим CSV, но модуль может также хорошо это проанализировать, с вариантами выбора ниже.
use warnings;
use strict;
use feature 'say';
use Text::CSV;
my $file = shift || 'data.txt';
my $outfile = 'new_' . $file;
my $csv = Text::CSV->new( { binary => 1, sep_char => '|',
allow_loose_quotes => 1, escape_char => '', # quotes inside fields
always_quote => 1 # output as desired
} ) or die "Can't do CSV: ", Text::CSV->error_diag;
open my $fh, '<', $file or die "Can't open $file: $!";
open my $out_fh, '>', $outfile or die "Can't open $outfile: $!";
while (my $row = $csv->getline($fh)) {
s/`/``/g for @$row;
tr/"/`/ for @$row;
$csv->say($out_fh, $row);
}
Для работы с кавычками внутри полей escape_char
должен отличаться от quote_char
;Я просто установил здесь значение ''
.Выходные данные также обрабатываются модулем, и атрибут always_quote
предназначен для этого (чтобы процитировать все поля, необходимые или нет).Пожалуйста, смотрите документацию.
Конечно, с этим модулем можно сделать гораздо больше.
Если цель вопроса состоит именно в том, чтобы очистить формат файла, в котором одинаковые кавычки используются как для полей, так и внутри полей, я бы предложил сделать все это с помощью модуля.Такой подход позволяет четко и последовательно настроить все виды опций, как для ввода, так и для вывода, и его можно обслуживать.
Несколько вопросов
Чтокакие данные есть и есть ли возможность иметь случайную цитату?Тогда что?Это может повлиять даже на выбор оптимального подхода, поскольку может потребовать детального анализа.
Если задача состоит в том, чтобы выпрямить данные в стиле CSV, то почему бы не удвоить кавычки внутри полей?как обычное и правильное в CSV, вместо того, чтобы заменить их (и потенциально повредить их текстовое значение)?См., Например, документы модуля.