Kirjautuminen

Haku

Tehtävät

Keskustelu: Nettisivujen teko: Tekstikappaleet ja koodilohkot taulukkoon PHP:ssä

HTML5 [21.06.2016 23:06:04]

#

On merkkijono, jonka rivinvaihdot ovat LF-muodossa. Tekstikappaleet erotetaan toisistaan tyhjällä (taikka pelkkiä välilyöntejä tai sarkainmerkkejä sisältävällä) rivillä, ja koodit sijoitetaan kahden omalla rivillään olevan ```-merkinnän väliin.

Haluaisin kappaleet taulukkoon.

Merkkijono voi olla esimerkiksi tällainen:

Donec lacinia congue est *in sollicitudin*. Sed mi `diam` fermentum.

Integer interdum leo a ante efficitur, eget rhoncus mi dictum.
Sed sed lorem nec urna scelerisque imperdiet.

```
foo
    bar

baz
```

Siitä pitäisi tuottaa taulukko, joka sisältää seuraavat merkkijonot:

Donec lacinia congue est *in sollicitudin*. Sed mi `diam` fermentum.
Integer interdum leo a ante efficitur, eget rhoncus mi dictum.
Sed sed lorem nec urna scelerisque imperdiet.
```
foo
    bar

baz
```

Koodilohkon avausmerkinnän jälkeen voi olla kielen tunnus, esimerkiksi ```html.

Vaikeuksia tuottaa se, että ennen avaavaa ```-merkintää tai sulkevan sellaisen jälkeen ei välttämättä ole tyhjää riviä. Lisäksi koodilohkossa niitä on usein.

Kuinka toteuttaisin tämän?

groovyb [22.06.2016 01:35:00]

#

Noh, Mikset käytä erottimena lf:n lisäksi ''' tunnistetta?

jlaire [22.06.2016 01:46:56]

#

Jos kyseessä on Markdown, kannattaa käyttää valmista parseria.

Tai koodaa itse. Voit käyttää tätä esimerkkiä pohjana.

<?php

$blocks = array();
$inside_code = false;
$current_block = array();

function end_block() {
  global $current_block;
  global $blocks;
  if (!empty($current_block)) {
    $blocks[] = implode('\n', $current_block);
    $current_block = array();
  }
}

while (($line = fgets(STDIN)) !== false) {
  $line = preg_replace('/\n$/', '', $line);
  if (substr($line, 0, 3) === '```') {
    if ($inside_code) {
      $current_block[] = $line;
      end_block();
      $inside_code = false;
    }
    else {
      end_block();
      $inside_code = true;
      $current_block[] = $line;
    }
  }
  else if ($line === '' && !$inside_code) {
    end_block();
  }
  else {
    $current_block[] = $line;
  }
}

end_block();

print_r($blocks);

HTML5 [22.06.2016 02:05:36]

#

jlaire kirjoitti:

Jos kyseessä on Markdown, kannattaa käyttää valmista parseria.

Tai koodaa itse. Voit käyttää tätä esimerkkiä pohjana.

– –

Tarkoitus on mahdollistaa perusmuotoilut blogin kommentteihin:

Koodilohkojen sisällä muotoilujen ei tule toimia.

Syntaksi on otettu MarkDownista. En halua käyttää valmista parseria, koska tarvitsen vain muutamia muotoiluja ja haluan päättää itse syntaksin.

jlaire [22.06.2016 02:28:12]

#

Eli et osaa toteuttaa parseria ilman apua, mutta valmis ratkaisu ei kelpaa? Jaa-a.

Markdownin syntaksista on jo useampi eri variaatio, uuden keskiminen on aika vaikeaa perustella. Voit joka tapauksesas ottaa jonkun avoimen lähdekoodin parserin ja muokata sitä.

Metabolix [22.06.2016 13:26:06]

#

Tällainen muotoilu on ”helppo” tehdä kahdessa osassa säännöllisillä lausekkeilla. Ensimmäinen vaihe on erottaa lohkot, toinen vaihe on erottaa rivin sisällä olevat muotoilut. Mutkikkain ominaisuus on oikeastaan escape, ja siinä saakin tarkkaan miettiä, miten virheelliset escapet käsitellään. Näytetäänkö \-merkki, näytetäänkö vain sitä seuraava merkki, vai aiheutuuko suoranainen virhe? Jos ei tule virhettä, vanhat viestit voivat mennä rikki, jos joskus escapeja lisätään. Seuraavassa koodissa kuitenkin virheelliset escapet näytetään kokonaisuudessaan.

<?php
function muotoile_rivi($s) {
	$s = preg_replace_callback(
		'/(`((?>\\\\\\\\|\\\\`|[^`])*)`)|(\\*((?>\\\\\\\\|\\\\\\*|[^\\*])*)\\*)|(\\\\([`\\*\\\\]))|(\\n)|([^`\\*\\\\]+|.)/',
		function($m) {
			if ($m[1]) {
				return "<code>".htmlspecialchars(preg_replace('/\\\\(\\\\|`)/', '$1', $m[2]))."</code>";
			}
			if ($m[3]) {
				return "<em>".htmlspecialchars(preg_replace('/\\\\(\\\\|\\*)/', '$1', $m[4]))."</em>";
			}
			if ($m[5]) {
				return htmlspecialchars($m[6]);
			}
			if ($m[7]) {
				return "<br />\n";
			}
			return htmlspecialchars($m[0]);
		},
		$s
	);
	return "<p>{$s}</p>";
}
function muotoile_koodi($s) {
	return "<pre>\n".htmlspecialchars($s)."\n</pre>";
}
function muotoile($s) {
	$re = '/\\s*^```\\n(.*?)\\n```$|\\s*^(.+?)(?:\\n\\n|\\n\\Z|\\Z)/sm';
	preg_match_all($re, $s, $m, PREG_SET_ORDER);

	$arr = [];
	foreach ($m as $m) {
		if (isset($m[2])) {
			$arr[] = muotoile_rivi($m[2]);
		} else {
			$arr[] = muotoile_koodi($m[1]);
		}
	}
	return implode("\n\n", $arr)."\n";
}

$s = '
HTML-testi: <b> `<b>` *<b>*
Escape-testi: `\\\\` == \\\\ ja `\*a*b\*c*` == \*a*b\*c*
Rivinvaihtotesti tuli samalla.

```
<b> kooditesti ja HTML-testi sen sisällä </b>
    sisennetty rivi
```
';

echo "<pre>".htmlspecialchars($s)."</pre>\n<hr />\n";
$t = muotoile($s);
echo "<pre>".htmlspecialchars($t)."</pre>\n<hr />\n";
echo $t;

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta