Skip to content

Instantly share code, notes, and snippets.

@karol-majewski
Last active July 29, 2020 14:38
Show Gist options
  • Save karol-majewski/afaff207cd2c22656bd8262ee263826b to your computer and use it in GitHub Desktop.
Save karol-majewski/afaff207cd2c22656bd8262ee263826b to your computer and use it in GitHub Desktop.
Creating exhaustive records with TypeScript (parenthesis matching problem, https://medium.com/@paulrohan/parenthesis-matching-problem-in-javascript-the-hacking-school-hyd-7d7708278911)
type Opening = '(' | '{' | '[';
type Closing = ')' | '}' | ']';
type Parenthesis = Opening | Closing;
const parentheses: Record<Opening, Closing> = {
'(': ')',
'[': ']',
'{': '}',
};
const isOpening = (parenthesis: Parenthesis): parenthesis is Opening =>
parenthesis in parentheses;
const matches = (word: string): boolean => {
const stack: Opening[] = [];
for (let i = 0; i < word.length; i++) {
const char = word[i] as Parenthesis;
if (isOpening(char)) {
stack.push(char);
} else {
const last = stack.pop();
if (last === undefined || char !== parentheses[last]) {
return false;
}
}
}
if (stack.length !== 0) {
return false;
}
return true;
}
console.log(matches("(){}")); // true
console.log(matches("[{()()}({[]})]({}[({})])((((((()[])){}))[]{{{({({({{{{{{}}}}}})})})}}}))[][][]")); // true
console.log(matches("({(()))}}")); // false
@karol-majewski
Copy link
Author

karol-majewski commented Jul 29, 2020

Same, but matching HTML tags. This version returns the first tag that needs to be changed.

type Opening =
  | '<div>'
  | '<p>'
  | '<b>'
  | '<em>'
  | '<i>';

type Closing =
  | '</div>'
  | '</p>'
  | '</b>'
  | '</em>'
  | '</i>';

type Tag = Opening | Closing;

const tags: Record<Opening, Closing> = {
  "<div>": '</div>',
  "<p>": '</p>',
  "<b>": '</b>',
  "<em>": '</em>',
  "<i>": '</i>',
}

function isOpening(tag: Tag): tag is Opening {
  return tag in tags;
}

function strip(tag: Tag): string {
  return tag.match(/\w+/g)![0] as string;
}

const HTML_TAG_PATTERN = /(<.*?>)/g;

function HTMLElements(input: string): string | true {
  const tokens: Tag[] = input.match(HTML_TAG_PATTERN) as Tag[];
  const stack: Opening[] = [];

  for (const token of tokens) {
    if (isOpening(token)) {
      stack.push(token)
    } else {
      const last = stack.pop();

      if (last === undefined) {
        return strip(token);
      }

      if (tags[last] !== token) {
        return strip(last);
      }
    }
  }

  if (stack.length > 0) {
    return strip(stack[0]);
  }

  return true;
}

console.log(
  HTMLElements("<div><b><p>hello world</p></b></div>"),
)

   
// keep this function call here 
// @ts-ignore
console.log(HTMLElements(readline()));

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment