App-TextTableUtils
view release on metacpan or search on metacpan
script/csv2dd view on Meta::CPAN
#!perl
use 5.010001;
use strict;
use warnings;
our $AUTHORITY = 'cpan:PERLANCAR'; # AUTHORITY
our $DATE = '2023-12-03'; # DATE
our $DIST = 'App-TextTableUtils'; # DIST
our $VERSION = '0.010'; # VERSION
my ($ifmt, $ofmt) = $0 =~ /(\w+)2(\w+)\z/ or die "Please call me as <foo>2<bar> (not $0)";
# parse options
my %Opts;
{
require Getopt::Long;
Getopt::Long::Configure("bundling", "no_ignore_case", "permute", "no_getopt_compat");
Getopt::Long::GetOptions(
"backend|b=s" => \$Opts{backend},
"transpose|t" => \$Opts{transpose},
"csv-sep|s=s" => \$Opts{csv_sep},
"csv-quote|q=s" => \$Opts{csv_quote},
"csv-escape|e=s" => \$Opts{csv_escape},
"csv-loose|l" => \$Opts{csv_loose}
) or die "$0: Error in getting options, bailing out\n";
}
# get input handle
my $fh;
{
if (@ARGV == 1) {
open $fh, "<:encoding(utf8)", $ARGV[0] or die "Can't open $ARGV[0]: $!";
} elsif (!@ARGV) {
binmode(STDIN, ":encoding(utf8)");
$fh = \*STDIN;
} else {
die "Usage: $0 <filename>\n";
}
}
my $rows;
# parse input into rows
{
if ($ifmt eq 'csv') {
require Text::CSV;
my $csv = Text::CSV->new({ binary => 1 })
or die "Cannot use CSV: ".Text::CSV->error_diag;
if ($Opts{csv_sep}) {
$csv->sep_char($Opts{csv_sep});
}
if ($Opts{csv_quote}) {
$csv->quote_char($Opts{csv_quote});
}
if ($Opts{csv_escape}) {
$csv->escape_char($Opts{csv_escape});
}
if ($Opts{csv_loose}) {
$csv->allow_loose_quotes(1);
$csv->allow_loose_escapes(1);
}
$rows = [];
while ( my $row = $csv->getline($fh) ) {
push @$rows, $row;
}
$csv->eof or $csv->error_diag();
} elsif ($ifmt eq 'tsv') {
$rows = [];
while (my $row = <$fh>) {
chomp $row;
push @$rows, [split /\t/, $row];
}
} elsif ($ifmt eq 'ini' || $ifmt eq 'iod') {
my $reader;
if ($ifmt eq 'ini') {
require Config::IOD::INI::Reader;
$reader = Config::IOD::INI::Reader->new;
} else {
require Config::IOD::Reader;
$reader = Config::IOD::Reader->new;
}
my $content = do { local $/; scalar <$fh> };
my $hoh = $reader->read_string($content);
$rows = [];
for my $section (sort keys %$hoh) {
my $hash = $hoh->{$section};
for my $key (sort keys %$hash) {
push @$rows, [$key, $hash->{$key}];
}
}
} elsif ($ifmt eq 'json') {
require Data::Check::Structure;
require JSON::MaybeXS;
local $/;
$rows = JSON::MaybeXS::decode_json(scalar <$fh>);
die "Input data is not an array-of-arrays-of scalars"
unless Data::Check::Structure::is_aoaos($rows);
} elsif ($ifmt eq 'dd') {
require Data::Check::Structure;
local $/;
$rows = eval scalar <$fh>; ## no critic: BuiltinFunctions::ProhibitStringyEval
die if $@;
die "Input data is not an array-of-arrays-of scalars"
unless Data::Check::Structure::is_aoaos($rows);
} else {
die "Unknown input format '$ifmt'";
}
}
# optionally transpose
if ($Opts{transpose}) {
my $new_rows = [];
for my $i (0..$#{$rows}) {
my $row = $rows->[$i];
for my $j (0..$#{$row}) {
$new_rows->[$j][$i] = $row->[$j];
}
}
$rows = $new_rows;
script/csv2dd view on Meta::CPAN
=item 32. L<json2mdtable>
=item 33. L<json2orgtable>
=item 34. L<json2texttable>
=item 35. L<json2tsv>
=item 36. L<texttableutils-convert>
=item 37. L<tsv2ansitable>
=item 38. L<tsv2asciitable>
=item 39. L<tsv2dd>
=item 40. L<tsv2json>
=item 41. L<tsv2mdtable>
=item 42. L<tsv2orgtable>
=item 43. L<tsv2texttable>
=back
Some examples for using the scripts:
To render CSV as Org table:
% csv2orgtable TABLE.CSV
To render CSV as JSON:
% csv2json < TABLE.CSV
To render TSV as a text table (using L<Text::Table::Any>) with LTSV backend:
% echo "SELECT * FROM table1" | mysql DBNAME | tsv2texttable -b Text::Table::LTSV
=head1 OPTIONS
=head2 --backend (-b)
Only for texttable output (C<*2texttable> scripts).
Select L<Text::Table::Any> backend to use.
=head2 --transpose (-t)
Transpose table prior to output.
=head2 --csv-sep (-s)
Use the character(s) specified by this option, when input is a CSV files with a
different separator.
=head2 --csv-loose (-l)
Enable C<allow_loose_escapes> and C<allow_loose_quotes> in L<Text::CSV> (the
backend used to read CSV files).
=head1 HOMEPAGE
Please visit the project's homepage at L<https://metacpan.org/release/App-TextTableUtils>.
=head1 SOURCE
Source repository is at L<https://github.com/perlancar/perl-App-TextTableUtils>.
=head1 SEE ALSO
L<App::texttable>, L<texttable>
=head1 AUTHOR
perlancar <perlancar@cpan.org>
=head1 CONTRIBUTING
To contribute, you can send patches by email/via RT, or send pull requests on
GitHub.
Most of the time, you don't need to build the distribution yourself. You can
simply modify the code, then test via:
% prove -l
If you want to build the distribution (e.g. to try to install it locally on your
system), you can install L<Dist::Zilla>,
L<Dist::Zilla::PluginBundle::Author::PERLANCAR>,
L<Pod::Weaver::PluginBundle::Author::PERLANCAR>, and sometimes one or two other
Dist::Zilla- and/or Pod::Weaver plugins. Any additional steps required beyond
that are considered a bug and can be reported to me.
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2023, 2022, 2021, 2019, 2016 by perlancar <perlancar@cpan.org>.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=head1 BUGS
Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=App-TextTableUtils>
When submitting a bug or request, please include a test-file or a
patch to an existing test-file that illustrates the bug or desired
feature.
=cut
( run in 0.823 second using v1.01-cache-2.11-cpan-39bf76dae61 )