View source for Formatter: CSV

#||
||
Compatible with: !!(green)**R6.1**!!
Current version: **0.3** (beta)
Credits: http://docs.wikkawiki.org/FormatterCSV
|{{toc numerate=1}} ||
||#

This formatter converts inline CSV data into a table.

===Features===
  * supports both ##comma## (default) and ##semicolon## as separator
  * rows of the table alternate background color
  * column alignment: ##\##left##\##, ##/##right##/##, ##""|""##center##""|""## or default
  * table headers/footers using wiki style ##""==""##heading markers##""==""##
  * add comments in between data by starting a line with (##""#""##); blank lines are ignored
  * cells can be surrounded in double quotes (##"##); text in quotes is preserved e.g., whitespace, no splitting on the separator
  * it is possible to escape a separator with a backslash (##\##), that should appear in text
  * wiki links in cell text are linked to their internal wiki pages

===Usage===
Call via ##(csv [delim=[comma|semicolon])##

##""%%(csv delim="semicolon") source%%""##

((source:master/community/formatter/highlight/csv.php formatter/highlight/csv.php))
``(php)
<?php

/*
	converts inline csv data into a table

	%%(csv
		[delim="comma|semicolon"]
		)
	content
	%%

	https://wackowiki.org/doc/Dev/PatchesHacks/CSV
*/

$options['delim']	??= 'comma';

$delim	= match($options['delim']) {
	'semicolon'	=> ';',
	default		=> ',',
};

$blanks		= 0;
$csv_lines	= preg_split('/[\n]/', $text);

// asserts what precedes the ; is not a backslash \\\\, doesn't account for \\; (escaped backslash semicolon)
// https://stackoverflow.com/questions/40479546/how-to-split-on-white-spaces-not-between-quotes

// split on delimiter but not between quotes
$regex_split	= '/(?<!\\\\)' . $delim . '(?=(?:[^\"]*([\"])[^\"]*\\1)*[^\"]*$)/';
$regex_escaped	= '/\\\\' . $delim . '/';

$tpl->enter('r_');

foreach ($csv_lines as $i => $line)
{
	if (preg_match('/^#|^\s*$/', $line))
	{
		$blanks++;
		continue;
	}

	$tpl->commit = true; // alternation hack

	$tpl->enter('c_');

	foreach (preg_split($regex_split, $line) as $r => $field)
	{
		$tpl->commit = true; // alternation hack

		if ($i == $blanks)
		{
			$class[$r] = ''; // 'padding: 1px 10px 1px 10px; ';
		}

		if (preg_match('/^\"?\s*==(.*)==\s*\"?$/', $field, $header))
		{
			$title[$r] = $header[1];

			if (preg_match('/([\/\\\\|])(.*)\\1$/', $title[$r], $align))
			{
				$class[$r] .= match($align[1]) {
					'/'		=> 't-right',
					'\\'	=> 't-left',
					'|'		=> 't-center',
				};

				$title[$r] = $align[2];
			}

			$tpl->h_class	= $class[$r];
			$tpl->h_title	= $title[$r];
			continue;
		}

		// if a cell is blank, echo NBSP
		if (preg_match('/^\s*$/', $field))
		{
			$tpl->t_class	= $class[$r];
			$tpl->t_cell	= "\u{00A0}";
			continue;
		}
		// extract the cell out of it's quotes
		else if (preg_match('/^\s*(\"?)(.*?)\\1\s*$/', $field, $matches))
		{
			if ($matches[1] == '"')
			{
				#$style[$r]	= 'white-space: pre; ' . $style[$r];
				$cell		= $matches[2];
			}
			else
			{
				$cell		= preg_replace($regex_escaped, $delim, $matches[2]);
			}

			// [[wiki link]]
			if (preg_match_all('/\[\[([[:alnum:]]+)\]\]/', $cell, $all_links))
			{
				$linked = $cell;

				foreach ($all_links[1] as $camel_link)
				{
					$linked = preg_replace('/\[\[' . $camel_link . '\]\]/', $this->link($camel_link), $linked);
				}
			}
			// [[url label]]
			else if (preg_match_all('/\[\[(.*?)\]\]/', $cell, $all_links))
			{
				$linked = $cell;

				foreach ($all_links[1] as $url_link)
				{
					if(preg_match('/^(\S+)(\s+(.+))?$/us', $url_link, $matches))
					{
						$url	= $matches[1] ?? '';
						$text	= $matches[3] ?? '';
						$linked	= preg_replace('#\[\[' . $matches[0] . '\]\]#', $this->link($url, '', $text), $linked);
					}
				}
			}
			else
			{
				$linked = Ut::html($cell);
			}

			$tpl->t_class	= $class[$r];
			$tpl->t_cell	= $linked;
			continue;
		}

		$tpl->t_class	= $class[$r];
		$tpl->t_cell	= 'ERROR!';
	}

	$tpl->leave();	// c_
}

$tpl->leave();	// r_

``


((source:master/community/formatter/highlight/template/csv.tpl formatter/highlight/template/csv.tpl))
%%
[ === main === ]
<ignore>
	<!--notypo-->
	<table class="usertable">
		<tbody>
		[= r _ =
			[ ' commit | void ' ]
			<tr>
			[= c _ =
				[ ' commit | void ' ]
				[= h _ =
					<th class="[ ' class ' ]">[ ' title | e ' ]</th>
				=]
				[= t _ =
					<td class="[ ' class ' ]">[ ' cell ' ]</td>
				=]
			=]
			</tr>
		=]
		</tbody>
	</table>
	<!--/notypo-->
</ignore>

%%

====local usage of repository====
Symlink the formatter from community folder in the **src/formatter/highlight** folder and the corresponding template in the **src/formatter/highlight/template** folder in your repo.
%%
ln -s ../../../community/formatter/highlight/csv.php csv.php
ln -s ../../../../community/formatter/highlight/template/csv.tpl csv.tpl
%%

===Example===
##""%%(csv delim="semicolon")
;	==/First Name/==;	==\Last Name\==;	==|Address|==;	== Age ==
==Norwegian==;	Sigurd;	Nordmo;	[[Viggo]],\, Hansteens allé 119\; 1524 MOSS;	38
==Swede==;	Chanelle;	Blomqvist;	Överhogdal 95\; 282 02 HÖRJA;	61
==German==;	Leah;	Ackermann;	"Landhausstraße 73; 15702 Königs Wusterhausen";	25
# Comments are possible. Yes, the following person is a Hobbit!
==Hobbit==;	Celendine;	"Gam gee";	;	216
%%""##

%%(csv delim="semicolon")
;	==/First Name/==;	==\Last Name\==;	==|Address|==;	== Age ==
==Norwegian==;	Sigurd;	Nordmo;	[[Viggo]],\, Hansteens allé 119\; 1524 MOSS;	38
==Swede==;	Chanelle;	Blomqvist;	Överhogdal 95\; 282 02 HÖRJA;	61
==German==;	Leah;	Ackermann;	"Landhausstraße 73; 15702 Königs Wusterhausen";	25
# Comments are possible. Yes, the following person is a Hobbit!
==Hobbit==;	Celendine;	"Gam gee";	;	216
%%

===Changelog===
0.1	Backported from WikkaWiki
0.2  Simplified & updated to work with PHP 8 (Null coalescing assignment operator, Match expression)
0.3 Added template

===To Do===
  * fix link parsing
  * add additional ##$options['parameter']## and CSS class styles
  * modify the formatter for your purpose

{{backlinks}}