Skip to main content
improved formatting
Source Link
Arnauld
  • 206.3k
  • 21
  • 189
  • 673
  • one with 10 entries to identify the BBCode tagstag names
  • one with 20 entries for the corresponding opening HTML tags, with and without a BBCode parameter
s =>
// split the input string on pseudo-legal BBCode tags '[…]'
(a = s.split(/(\[.+?\])/))
// for each part s at index i
.map(S = (s, i) =>
  i & 1 ?
    // if this is a tag
    (
      // C = 'closing tag' flag, t = tag name, p = optional parameter
      [, C, t,, p] = /.(\/)?(\w+)(=(.+))?./.exec(s),
      // force t to lowercase and get n = internal BBCode tag ID
      n =
      // 0   1     2    3 4 5     6   7 8 9
        `url|color|size|b|i|quote|img|u|s|code`
        .split`|`
        .indexOf(t = t.toLowerCase()),
      C
    ) ?
      // if this is a closing tag
      !(
        // attempt to retrieve j = position of the opening tag
        // and p = parameter of the opening tag
        [j, p] = S[t]?.pop() || [],
        // T = HTML tag determined by n and the presence of a parameter
        // (NB: an 'url'entry tag#0 isshould alwaysbe forcedequal to entry #1, but we just
        // convert 0 to 1 to save bytes)
        T =
        //  1           3      5          6       8
          `|a href="0"||21:0"||2font-1:0"|strong||em||` +
        // 10     11                   12         14 16 18
          `block1|block1><cite>0</cite|1 src="0"||u||s||1`
          .split`|`
          [n * 2 | !!p || 1]
          // unpack the digits:
          //   0 → p or a[j + 1],
          //   1 → t,
          //   2 → 'span style="'
          ?.replace(
            /\d/g,
            n => [ p || a[j + 1], t, 'span style="'][n]
        ),
        // decrement c if it's greater than 0 and the tag is 'code'
        c -= c && n > 8
      ) * j && T ?
        // if c is not 0 and both j and T are defined,
        // replace the opening tag with T
        a[a[j] = `<${T}>`, i] =
          n - 6 ?
            // if this is not an 'img' tag, update the closing tag
            // using the name extracted from T
            `</${/\w+/.exec(T)}>`
          :
            // otherwise, clear both a[j + 1] and the closing tag
            a[j + 1] = ''
      :
        // invalid tag: do nothing
        0
    :
      // opening tag: push [i, p] onto this tag's stack
      // and increment c if the tag is 'code'
      (c += n > 8, S[t] ||= []).push([i, p])
  :
    // this is not a tag: do nothing
    0,
  // c = code block counter, initialized to 0
  c = 0
)
// end of map(), return a[] joined
&& a.join``
  • one with 10 entries to identify the BBCode tags
  • one with 20 entries for the corresponding HTML tags, with and without a BBCode parameter
s =>
// split the input string on pseudo-legal BBCode tags '[…]'
(a = s.split(/(\[.+?\])/))
// for each part s at index i
.map(S = (s, i) =>
  i & 1 ?
    // if this is a tag
    (
      // C = 'closing tag' flag, t = tag name, p = optional parameter
      [, C, t,, p] = /.(\/)?(\w+)(=(.+))?./.exec(s),
      // force t to lowercase and get n = internal BBCode tag ID
      n =
      // 0   1     2    3 4 5     6   7 8 9
        `url|color|size|b|i|quote|img|u|s|code`
        .split`|`
        .indexOf(t = t.toLowerCase()),
      C
    ) ?
      // if this is a closing tag
      !(
        // attempt to retrieve j = position of the opening tag
        // and p = parameter of the opening tag
        [j, p] = S[t]?.pop() || [],
        // T = HTML tag determined by n and the presence of a parameter
        // (NB: an 'url' tag is always forced to entry #1)
        T =
        //  1           3      5          6       8
          `|a href="0"||21:0"||2font-1:0"|strong||em||` +
        // 10     11                   12         14 16 18
          `block1|block1><cite>0</cite|1 src="0"||u||s||1`
          .split`|`
          [n * 2 | !!p || 1]
          // unpack: 0 → p or a[j + 1], 1 → t, 2 → 'span style="'
          ?.replace(/\d/g, n => [ p || a[j + 1], t, 'span style="'][n]),
        // decrement c if it's greater than 0 and the tag is 'code'
        c -= c && n > 8
      ) * j && T ?
        // if c is not 0 and both j and T are defined,
        // replace the opening tag with T
        a[a[j] = `<${T}>`, i] =
          n - 6 ?
            // if this is not an 'img' tag, update the closing tag
            // using the name extracted from T
            `</${/\w+/.exec(T)}>`
          :
            // otherwise, clear both a[j + 1] and the closing tag
            a[j + 1] = ''
      :
        // invalid tag: do nothing
        0
    :
      // opening tag: push [i, p] onto this tag's stack
      // and increment c if the tag is 'code'
      (c += n > 8, S[t] ||= []).push([i, p])
  :
    // this is not a tag: do nothing
    0,
  // c = code block counter, initialized to 0
  c = 0
)
// end of map(), return a[] joined
&& a.join``
  • one with 10 entries to identify the BBCode tag names
  • one with 20 entries for the corresponding opening HTML tags, with and without a BBCode parameter
s =>
// split the input string on pseudo-legal BBCode tags '[…]'
(a = s.split(/(\[.+?\])/))
// for each part s at index i
.map(S = (s, i) =>
  i & 1 ?
    // if this is a tag
    (
      // C = 'closing tag' flag, t = tag name, p = optional parameter
      [, C, t,, p] = /.(\/)?(\w+)(=(.+))?./.exec(s),
      // force t to lowercase and get n = internal BBCode tag ID
      n =
      // 0   1     2    3 4 5     6   7 8 9
        `url|color|size|b|i|quote|img|u|s|code`
        .split`|`
        .indexOf(t = t.toLowerCase()),
      C
    ) ?
      // if this is a closing tag
      !(
        // attempt to retrieve j = position of the opening tag
        // and p = parameter of the opening tag
        [j, p] = S[t]?.pop() || [],
        // T = HTML tag determined by n and the presence of a parameter
        // (NB: entry #0 should be equal to entry #1, but we just
        // convert 0 to 1 to save bytes)
        T =
        //  1           3      5          6       8
          `|a href="0"||21:0"||2font-1:0"|strong||em||` +
        // 10     11                   12         14 16 18
          `block1|block1><cite>0</cite|1 src="0"||u||s||1`
          .split`|`
          [n * 2 | !!p || 1]
          // unpack the digits:
          //   0 → p or a[j + 1]
          //   1 → t
          //   2 → 'span style="'
          ?.replace(
            /\d/g,
            n => [ p || a[j + 1], t, 'span style="'][n]
        ),
        // decrement c if it's greater than 0 and the tag is 'code'
        c -= c && n > 8
      ) * j && T ?
        // if c is not 0 and both j and T are defined,
        // replace the opening tag with T
        a[a[j] = `<${T}>`, i] =
          n - 6 ?
            // if this is not an 'img' tag, update the closing tag
            // using the name extracted from T
            `</${/\w+/.exec(T)}>`
          :
            // otherwise, clear both a[j + 1] and the closing tag
            a[j + 1] = ''
      :
        // invalid tag: do nothing
        0
    :
      // opening tag: push [i, p] onto this tag's stack
      // and increment c if the tag is 'code'
      (c += n > 8, S[t] ||= []).push([i, p])
  :
    // this is not a tag: do nothing
    0,
  // c = code block counter, initialized to 0
  c = 0
)
// end of map(), return a[] joined
&& a.join``
minor update
Source Link
Arnauld
  • 206.3k
  • 21
  • 189
  • 673
s =>
// split the input string on pseudo-legal BBCode tags '[…]'
(a = s.split(/(\[.+?\])/))
// for each part s at index i
.map(S = (s, i) =>
  i & 1 ?
    // if this is a tag
    (
      // C = 'closing tag' flag, t = tag name, p = optional parameter
      [, C, t,, p] = /.(\/)?(\w+)(=(.+))?./.exec(s),
      // force t to lower caselowercase and get n = internal BBCode tag ID
      n =
      // 0   1     2    3 4 5     6   7 8 9
        `url|color|size|b|i|quote|img|u|s|code`
        .split`|`
        .indexOf(t = t.toLowerCase()),
      C
    ) ?
      // if this is a closing tag
      !(
        // attempt to retrieve j = position of the opening tag
        // and p = parameter inof the opening tag
        [j, p] = S[t]?.pop() || [],
        // T = HTML tag accordingdetermined toby n and the presence of a parameter
        // (NB: an 'url' tag is always forced to entry #1)
        T =
        //  1           3      5          6       8
          `|a href="0"||21:0"||2font-1:0"|strong||em||` +
        // 10     11                   12         14 16 18
          `block1|block1><cite>0</cite|1 src="0"||u||s||1`
          .split`|`
          [n * 2 | !!p || 1]
          // unpack: 0 → p or a[j + 1], 1 → t, 2 → 'span style="'
          ?.replace(/\d/g, n => [ p || a[j + 1], t, 'span style="'][n]),
        // decrement c if it's greater than 0 and the tag is 'code'
        c -= c && n > 8
      ) * j && T ?
        // if c is not 0 and both j and T are defined,
        // replace the opening tag with T
        a[a[j] = `<${T}>`, i] =
          n - 6 ?
            // if this is not an 'img' tag, update the closing tag
            // using the name extracted from T
            `</${/\w+/.exec(T)}>`
          :
            // otherwise, clear both a[j + 1] and the closing tag
            a[j + 1] = ''
      :
        // invalid tag: do nothing
        0
    :
      // opening tag: incrementpush c[i, ifp] theonto tagthis istag's 'code'stack
      // and push [i,increment p]c intoif thisthe tag stackis 'code'
      (c += n > 8, S[t] ||= []).push([i, p])
  :
    // this is not a tag: do nothing
    0,
  // c = code block counter, initialized to 0
  c = 0
)
// end of map(), return a[] joined
&& a.join``
s =>
// split the input string on pseudo-legal BBCode tags '[…]'
(a = s.split(/(\[.+?\])/))
// for each part s at index i
.map(S = (s, i) =>
  i & 1 ?
    // if this is a tag
    (
      // C = 'closing tag' flag, t = tag name, p = optional parameter
      [, C, t,, p] = /.(\/)?(\w+)(=(.+))?./.exec(s),
      // force t to lower case and get n = internal BBCode tag ID
      n =
      // 0   1     2    3 4 5     6   7 8 9
        `url|color|size|b|i|quote|img|u|s|code`
        .split`|`
        .indexOf(t = t.toLowerCase()),
      C
    ) ?
      // if this is a closing tag
      !(
        // attempt to retrieve j = position of the opening tag
        // and p = parameter in the opening tag
        [j, p] = S[t]?.pop() || [],
        // T = HTML tag according to n and the presence of a parameter
        // (NB: an 'url' tag is always forced to entry #1)
        T =
        //  1           3      5          6       8
          `|a href="0"||21:0"||2font-1:0"|strong||em||` +
        // 10     11                   12         14 16 18
          `block1|block1><cite>0</cite|1 src="0"||u||s||1`
          .split`|`
          [n * 2 | !!p || 1]
          // unpack: 0 → p or a[j + 1], 1 → t, 2 → 'span style="'
          ?.replace(/\d/g, n => [ p || a[j + 1], t, 'span style="'][n]),
        // decrement c if it's greater than 0 and the tag is 'code'
        c -= c && n > 8
      ) * j && T ?
        // if c is not 0 and both j and T are defined,
        // replace the opening tag with T
        a[a[j] = `<${T}>`, i] =
          n - 6 ?
            // if this is not an 'img' tag, update the closing tag
            // using the name extracted from T
            `</${/\w+/.exec(T)}>`
          :
            // otherwise, clear both a[j + 1] and the closing tag
            a[j + 1] = ''
      :
        // invalid tag: do nothing
        0
    :
      // opening tag: increment c if the tag is 'code'
      // and push [i, p] into this tag stack
      (c += n > 8, S[t] ||= []).push([i, p])
  :
    // this is not a tag: do nothing
    0,
  // c = code block counter, initialized to 0
  c = 0
)
// end of map(), return a[] joined
&& a.join``
s =>
// split the input string on pseudo-legal BBCode tags '[…]'
(a = s.split(/(\[.+?\])/))
// for each part s at index i
.map(S = (s, i) =>
  i & 1 ?
    // if this is a tag
    (
      // C = 'closing tag' flag, t = tag name, p = optional parameter
      [, C, t,, p] = /.(\/)?(\w+)(=(.+))?./.exec(s),
      // force t to lowercase and get n = internal BBCode tag ID
      n =
      // 0   1     2    3 4 5     6   7 8 9
        `url|color|size|b|i|quote|img|u|s|code`
        .split`|`
        .indexOf(t = t.toLowerCase()),
      C
    ) ?
      // if this is a closing tag
      !(
        // attempt to retrieve j = position of the opening tag
        // and p = parameter of the opening tag
        [j, p] = S[t]?.pop() || [],
        // T = HTML tag determined by n and the presence of a parameter
        // (NB: an 'url' tag is always forced to entry #1)
        T =
        //  1           3      5          6       8
          `|a href="0"||21:0"||2font-1:0"|strong||em||` +
        // 10     11                   12         14 16 18
          `block1|block1><cite>0</cite|1 src="0"||u||s||1`
          .split`|`
          [n * 2 | !!p || 1]
          // unpack: 0 → p or a[j + 1], 1 → t, 2 → 'span style="'
          ?.replace(/\d/g, n => [ p || a[j + 1], t, 'span style="'][n]),
        // decrement c if it's greater than 0 and the tag is 'code'
        c -= c && n > 8
      ) * j && T ?
        // if c is not 0 and both j and T are defined,
        // replace the opening tag with T
        a[a[j] = `<${T}>`, i] =
          n - 6 ?
            // if this is not an 'img' tag, update the closing tag
            // using the name extracted from T
            `</${/\w+/.exec(T)}>`
          :
            // otherwise, clear both a[j + 1] and the closing tag
            a[j + 1] = ''
      :
        // invalid tag: do nothing
        0
    :
      // opening tag: push [i, p] onto this tag's stack
      // and increment c if the tag is 'code'
      (c += n > 8, S[t] ||= []).push([i, p])
  :
    // this is not a tag: do nothing
    0,
  // c = code block counter, initialized to 0
  c = 0
)
// end of map(), return a[] joined
&& a.join``
added a description of the method
Source Link
Arnauld
  • 206.3k
  • 21
  • 189
  • 673

Method

We split the input string on pseudo-legal BBCode tags, placing the tags at odd positions and the remaining parts at even positions. For instance:

[b][i]foo[/i][/b]["","[b]","","[i]","foo","[/i]","","[/b]",""]

We then iterate over the resulting array, modifying it in-place whenever a valid pair of opening and closing tags is found.

There is one stack per tag type in S, storing the position of each opening tag and its BBCode parameter, if any.

The counter c is used to keep track of the nesting depth of code blocks, allowing us to disable HTML conversion inside them.

We use two lookup tables:

  • one with 10 entries to identify the BBCode tags
  • one with 20 entries for the corresponding HTML tags, with and without a BBCode parameter

Commented

s =>
// split the input string on pseudo-legal BBCode tags '[…]'
(a = s.split(/(\[.+?\])/))
// for each part s at index i
.map(S = (s, i) =>
  i & 1 ?
    // if this is a tag
    (
      // C = 'closing tag' flag, t = tag name, p = optional parameter
      [, C, t,, p] = /.(\/)?(\w+)(=(.+))?./.exec(s),
      // force t to lower case and get n = internal BBCode tag ID
      n =
      // 0   1     2    3 4 5     6   7 8 9
        `url|color|size|b|i|quote|img|u|s|code`
        .split`|`
        .indexOf(t = t.toLowerCase()),
      C
    ) ?
      // if this is a closing tag
      !(
        // attempt to retrieve j = position of the opening tag
        // and p = parameter in the opening tag
        [j, p] = S[t]?.pop() || [],
        // T = HTML tag according to n and the presence of a parameter
        // (NB: an 'url' tag is always forced to entry #1)
        T =
        //  1           3      5          6       8
          `|a href="0"||21:0"||2font-1:0"|strong||em||` +
        // 10     11                   12         14 16 18
          `block1|block1><cite>0</cite|1 src="0"||u||s||1`
          .split`|`
          [n * 2 | !!p || 1]
          // unpack: 0 -> p or a[j + 1], 1 -> t, 2 -> 'span style="'
          ?.replace(/\d/g, n => [ p || a[j + 1], t, 'span style="'][n]),
        // decrement c if it's greater than 0 and the tag is 'code'
        c -= c && n > 8
      ) * j && T ?
        // if c is not 0 and both j and T are defined,
        // replace the opening tag with T
        a[a[j] = `<${T}>`, i] =
          n - 6 ?
            // if this is not an 'img' tag, update the closing tag
            // using the name extracted from T
            `</${/\w+/.exec(T)}>`
          :
            // otherwise, clear both a[j + 1] and the closing tag
            a[j + 1] = ''
      :
        // invalid tag: do nothing
        0
    :
      // opening tag: increment c if the tag is 'code'
      // and push [i, p] into this tag stack
      (c += n > 8, S[t] ||= []).push([i, p])
  :
    // this is not a tag: do nothing
    0,
  // c = code block counter, initialized to 0
  c = 0
)
// end of map(), return a[] joined
&& a.join``

Commented

s =>
// split the input string on pseudo-legal BBCode tags '[…]'
(a = s.split(/(\[.+?\])/))
// for each part s at index i
.map(S = (s, i) =>
  i & 1 ?
    // if this is a tag
    (
      // C = 'closing tag' flag, t = tag name, p = optional parameter
      [, C, t,, p] = /.(\/)?(\w+)(=(.+))?./.exec(s),
      // force t to lower case and get n = internal BBCode tag ID
      n =
      // 0   1     2    3 4 5     6   7 8 9
        `url|color|size|b|i|quote|img|u|s|code`
        .split`|`
        .indexOf(t = t.toLowerCase()),
      C
    ) ?
      // if this is a closing tag
      !(
        // attempt to retrieve j = position of the opening tag
        // and p = parameter in the opening tag
        [j, p] = S[t]?.pop() || [],
        // T = HTML tag according to n and the presence of a parameter
        T =
        //  1           3      5          6       8
          `|a href="0"||21:0"||2font-1:0"|strong||em||` +
        // 10     11                   12         14 16 18
          `block1|block1><cite>0</cite|1 src="0"||u||s||1`
          .split`|`
          [n * 2 | !!p || 1]
          // unpack: 0 -> p or a[j + 1], 1 -> t, 2 -> 'span style="'
          ?.replace(/\d/g, n => [ p || a[j + 1], t, 'span style="'][n]),
        // decrement c if it's greater than 0 and the tag is 'code'
        c -= c && n > 8
      ) * j && T ?
        // if c is not 0 and both j and T are defined,
        // replace the opening tag with T
        a[a[j] = `<${T}>`, i] =
          n - 6 ?
            // if this is not an 'img' tag, update the closing tag
            // using the name extracted from T
            `</${/\w+/.exec(T)}>`
          :
            // otherwise, clear both a[j + 1] and the closing tag
            a[j + 1] = ''
      :
        // invalid tag: do nothing
        0
    :
      // opening tag: increment c if the tag is 'code'
      // and push [i, p] into this tag stack
      (c += n > 8, S[t] ||= []).push([i, p])
  :
    // this is not a tag: do nothing
    0,
  // c = code block counter, initialized to 0
  c = 0
)
// end of map(), return a[] joined
&& a.join``

Method

We split the input string on pseudo-legal BBCode tags, placing the tags at odd positions and the remaining parts at even positions. For instance:

[b][i]foo[/i][/b]["","[b]","","[i]","foo","[/i]","","[/b]",""]

We then iterate over the resulting array, modifying it in-place whenever a valid pair of opening and closing tags is found.

There is one stack per tag type in S, storing the position of each opening tag and its BBCode parameter, if any.

The counter c is used to keep track of the nesting depth of code blocks, allowing us to disable HTML conversion inside them.

We use two lookup tables:

  • one with 10 entries to identify the BBCode tags
  • one with 20 entries for the corresponding HTML tags, with and without a BBCode parameter

Commented

s =>
// split the input string on pseudo-legal BBCode tags '[…]'
(a = s.split(/(\[.+?\])/))
// for each part s at index i
.map(S = (s, i) =>
  i & 1 ?
    // if this is a tag
    (
      // C = 'closing tag' flag, t = tag name, p = optional parameter
      [, C, t,, p] = /.(\/)?(\w+)(=(.+))?./.exec(s),
      // force t to lower case and get n = internal BBCode tag ID
      n =
      // 0   1     2    3 4 5     6   7 8 9
        `url|color|size|b|i|quote|img|u|s|code`
        .split`|`
        .indexOf(t = t.toLowerCase()),
      C
    ) ?
      // if this is a closing tag
      !(
        // attempt to retrieve j = position of the opening tag
        // and p = parameter in the opening tag
        [j, p] = S[t]?.pop() || [],
        // T = HTML tag according to n and the presence of a parameter
        // (NB: an 'url' tag is always forced to entry #1)
        T =
        //  1           3      5          6       8
          `|a href="0"||21:0"||2font-1:0"|strong||em||` +
        // 10     11                   12         14 16 18
          `block1|block1><cite>0</cite|1 src="0"||u||s||1`
          .split`|`
          [n * 2 | !!p || 1]
          // unpack: 0  p or a[j + 1], 1  t, 2  'span style="'
          ?.replace(/\d/g, n => [ p || a[j + 1], t, 'span style="'][n]),
        // decrement c if it's greater than 0 and the tag is 'code'
        c -= c && n > 8
      ) * j && T ?
        // if c is not 0 and both j and T are defined,
        // replace the opening tag with T
        a[a[j] = `<${T}>`, i] =
          n - 6 ?
            // if this is not an 'img' tag, update the closing tag
            // using the name extracted from T
            `</${/\w+/.exec(T)}>`
          :
            // otherwise, clear both a[j + 1] and the closing tag
            a[j + 1] = ''
      :
        // invalid tag: do nothing
        0
    :
      // opening tag: increment c if the tag is 'code'
      // and push [i, p] into this tag stack
      (c += n > 8, S[t] ||= []).push([i, p])
  :
    // this is not a tag: do nothing
    0,
  // c = code block counter, initialized to 0
  c = 0
)
// end of map(), return a[] joined
&& a.join``
minor update
Source Link
Arnauld
  • 206.3k
  • 21
  • 189
  • 673
Loading
added a commented version
Source Link
Arnauld
  • 206.3k
  • 21
  • 189
  • 673
Loading
saved 20 bytes
Source Link
Arnauld
  • 206.3k
  • 21
  • 189
  • 673
Loading
saved 8 bytes
Source Link
Arnauld
  • 206.3k
  • 21
  • 189
  • 673
Loading
saved 6 bytes
Source Link
Arnauld
  • 206.3k
  • 21
  • 189
  • 673
Loading
saved 6 bytes
Source Link
Arnauld
  • 206.3k
  • 21
  • 189
  • 673
Loading
Source Link
Arnauld
  • 206.3k
  • 21
  • 189
  • 673
Loading