DEV Community

Discussion on: Coding Puzzles: Week of 4/8

Collapse
 
aspittel profile image
Ali Spittel

Wednesday (6 KYU): Implement Syntax Highlighting

codewars.com/kata/roboscript-numbe...

Collapse
 
laurieontech profile image
Laurie • Edited

Booo regex

function highlight(code) {
  return code.replace(/(\D)\1+|(\d+|\D)/g, (substr) => {
      var color;
      let testChar = substr.charAt(0); 

      if (testChar === 'F') {
          color = 'pink';
      } else if (testChar === 'L') {
          color = 'red';
      } else if (testChar === 'R') {
          color = 'green';
      } else if (!isNaN(testChar)) {
          color = 'orange';
      } else {
        return substr;
      }
      return '<span style="color: ' + color + '">' + substr + '</span>';   
  })
}
Collapse
 
laurieontech profile image
Laurie • Edited

Quick edit with a dictionary.

function highlight(code) {
  const colorDict = {'F': 'pink', 'L': 'red', 'R':'green'};

  return code.replace(/(\D)\1*|\d+/g, (substr) => {
      let testChar = substr.charAt(0); 

      if (testChar in colorDict) {
        return '<span style="color: ' + colorDict[testChar] + '">' + substr + '</span>';   
      } else if (!isNaN(testChar)) {
        return '<span style="color: orange">' + substr + '</span>';   
      } else {
        return substr;
      }
  })
}
Collapse
 
threeheadedcerb profile image
russ

I had no idea you could use \1 in the same expression as the tagged group, never seen that before!

Thread Thread
 
laurieontech profile image
Laurie

Stackoverflow helped me with that one. I knew it was possible, but wasn't sure how. I actually started with the (.)\1* and iterated to the right regex from there.

Thread Thread
 
threeheadedcerb profile image
russ • Edited

You should be able to simplify it a little by changing the + to a * so you don't need the second \D I think?
(\D)\1*|(\d+)

Thread Thread
 
laurieontech profile image
Laurie

Ooh, you're right. I had it that way to start and then ran into problems with a test case that had 663. It was splitting that grouping because it hit the matching case first. But when I removed the capture group generic and made it non-digit that solved that. So can revert back. Thanks :)

Collapse
 
threeheadedcerb profile image
russ • Edited
import re

def highlight(cmd):
    colour_map = [
        (r'F+', 'pink'),
        (r'L+', 'red'),
        (r'R+', 'green'),
        (r'\d+', 'orange'),
        (r'()+', None),
    ]
    highlighted = []
    while(len(cmd)):
        for regex, colour in colour_map:
            match = re.match(regex, cmd)
            if match:
                idx_start, idx_end = match.span()
                highlighted.append((cmd[idx_start:idx_end], colour))
                cmd = cmd[idx_end:]
                break
        else:
            highlighted.append((cmd[0], None))
            cmd = cmd[1:]
    return ''.join(['<span style="color: {}">{}</span>'.format(colour, string) if colour else string for string, colour in highlighted])
Collapse
 
laurieontech profile image
Laurie

Oooh, I like this. I was thinking about a dictionary but didn't think about a dictionary with the regex as a key!

Collapse
 
threeheadedcerb profile image
russ

And now with added re.sub with a callable, which I had no idea was a thing! These coding things are pretty nifty for leaning new tricks I must say!

import re

def highlight(cmd):
    colour_map = [
        (r'F+', 'pink'),
        (r'L+', 'red'),
        (r'R+', 'green'),
        (r'\d+', 'orange'),
        (r'()+', None),
    ]

    def replacer(match : re.Match):
        substr = match.group()
        colour = next((colour for regex, colour in colour_map if re.match(regex, substr)), None)
        return '<span style="color: {}">{}</span>'.format(colour, substr) if colour else substr

    return re.sub(r'(\D)\1*|(\d+)', replacer, cmd)
Collapse
 
clandau profile image
Courtney

The answers to this kata on codewars are blowing my mind.

function highlight(code) {
    let codeString = '';
    let leftPointer, currentItem;
    let colorObj = {'F': '<span style=\"color: pink\">', 'L': '<span style=\"color: red\">', 'R': '<span style=\"color: green\">'};
    for(let i=0; i<code.length; i++){
        currentItem = code[i];
        if(!isNaN(code[i])) {
            codeString += '<span style=\"color: orange\">'
            leftPointer = i;
            while(i+1 < code.length && !isNaN(code[i+1])) {
                i++;
            }
            codeString += code.slice(leftPointer, i+1) + '</span>';
        }
        else if(colorObj[currentItem]) {
            codeString += colorObj[currentItem];
            while(i+1 < code.length && currentItem === code[i+1]) {
                i++;
                codeString += currentItem;
            }
        codeString += currentItem  + '</span>';
        }
        if(currentItem === '(' || currentItem === ')') codeString += currentItem;
    }
    return codeString;
  }