loading...

Daily Challenge #206 - Pound Means Backspace

thepracticaldev profile image dev.to staff ・1 min read

Assume "#" is like a backspace in string. This means that string "a#bc#d" would actually be "bd".

Implement a function that will process a string with "#" symbols and understand them as backspaces.

Examples

"abc#def##ghi###" ==> "abd"
"abc#d##c" ==> "ac"
"abc##d######" ==> ""
"#######" ==> ""
"" ==> ""

Tests

cleanString('abc#de##c')
cleanString('abc####dhh##c#')
cleanString('Thee# Empires# SS#tateBuildingg#')

Good Luck!


This challenge comes from vetalpaprotsky on CodeWars. Thank you to CodeWars, who has licensed redistribution of this challenge under the 2-Clause BSD License!

Want to propose a challenge idea for a future post? Email yo+challenge@dev.to with your suggestions!

Posted on by:

thepracticaldev profile

dev.to staff

@thepracticaldev

The hardworking team behind dev.to ❤️

Discussion

pic
Editor guide
 

Rust:

pub fn clean_string(text: &str) -> String {
    let mut result = String::new();
    for ch in text.chars() {
        if ch == '#' {
            result.pop();
        } else {
            result.push(ch);
        }
    }
    result
}

fn main() {
    assert_eq!(clean_string("abc#de##c"), "abc");
    assert_eq!(clean_string("abc####dhh##c#"), "d");
    assert_eq!(clean_string("Thee# Empires# SS#tateBuildingg#"), "The Empire StateBuilding");
}

Too easy...

 
 

Scala

  def cleanString (str: String): String = {
    (str.toList.foldLeft(List[Char]()) {
      case (Nil, '#')     => Nil
      case (x :: xs, '#') => xs
      case (xs, c)        => c :: xs
    }).reverse.mkString
  }
 

JavaScript with regex:

function cleanString(str)
{
  while(str.match(/[^#]#/))
  {
    str = str.split(/[^#]#/).join('');
  }
  str = str.replace(/^#+/, '');
  return str;
}
 

Try with

console.log(cleanString("########c"));
 
 

Progress 4GL

FUNCTION cleanString RETURNS CHARACTER
  (pcString AS CHARACTER):

  DEFINE VARIABLE i AS INTEGER   NO-UNDO.
  DEFINE VARIABLE c AS CHARACTER NO-UNDO.

  DO i = 1 TO LENGTH(pcString):
    CASE SUBSTRING(pcString,i,1):
      WHEN '#' THEN IF c > '' THEN c = SUBSTRING(c, 1, LENGTH(c) - 1).
      OTHERWISE c = c + SUBSTRING(pcString,i,1).
    END CASE. 
  END.

  RETURN c.
END FUNCTION. 

MESSAGE cleanString("abc#def##ghi###") = "abd" 
   SKIP cleanString("abc#d##c") = "ac"
   SKIP cleanString("abc##d######") = ""
   SKIP cleanString("#######") = ""
   SKIP cleanString("") = ""
   VIEW-AS ALERT-BOX INFORMATION BUTTONS OK.
 

Classic use case for a stack (Python).

def cleanString(string):
   chars = []
   for char in string:
      if char == '#' and len(chars):
         chars.pop()
      else:
         chars.append(char)
   return ''.join(chars)
 

A quick Clojure solution, leveraging a (linked) list as a stack:

(defn clean-string [s]
  (->> (reduce #(if (= \# %2) (pop %1) (conj %1 %2)) '() s)
       (reverse)
       (apply str)))
 

Hope this is right, C++

string cleanString(string s){
    string ans = ""; // the answer string
    int length = 0; // length of answer string
    for(char c : s){

        if(c == '#'){
            // if c == '#' and length > 0, then pop one character and decrement length
            if(length > 0){
                ans.pop_back();
                length--;
            }
        }
        // else add the character to string and increment length
        else{
            ans += c;
            length++;
        }
    }

    return ans;
}
 

Haskell:

cleanString :: String -> String
cleanString = reverse . clean 0 . reverse
  where
    clean :: Int -> String -> String
    clean _ "" = ""
    clean d ('#':rest) = clean (d + 1) rest
    clean 0 (ch:rest)  = ch : clean 0 rest
    clean d (ch:rest)  = clean (d - 1) rest
 

JavaScript

/**
 * Remove backspaces from a string
 * @param {String} string
 * @throws {Error} If the function gets called with more or less than one argument
 * @throws {TypeError} If the function gets called with a non-string argument
 * @return {String}
 */
function cleanString(string) {
    if (arguments.length !== 1) {
        throw new Error("Expected exactly one argument.");
    }

    if (typeof string !== "string") {
        throw new TypeError("Expected first argument to be a string.");
    }

    const characters = [];

    for (const character of string) {
        // If this is a character
        if (character !== "#") {
            characters.push(character);

            continue;
        }

        // If this is a backspace character
        // And that there is at least one character 
        if (characters.length) {
            characters.pop();
        }
    }

    return characters.join("");
}
 

Python – No doc strings etc., it's a challenge after all…

import re

def clean_text(text, _back_hash = re.compile(r'[^#]#')):
    changes = '#' in text
    while changes:
        text, changes = _back_hash.subn('', text)
    return text.replace('#', '')


def tests():
    data = (
        ("abc#def##ghi###", "abd"),
        ("abc#d##c", "ac"),
        ("abc##d######", ""),
        ("#######", ""),
        ("", ""),
    )
    for inp, out in data:
        assert clean_text(inp) == out, \
               f"{inp!r} cleaned is not {out!r} but {clean_text(inp)!r}"
    print('All tests OK!')


if __name__ == '__main__':
    for x in ('abc#de##c', 'abc####dhh##c#', 'Thee# Empires# SS#tateBuildingg#'):
        print(f"{x!r} ⇒ {clean_text(x)!r}")
    tests()
 

This is always a good idea to comment your code. Beginners trying to solve these challenges can learn a lot from veterans like you!

 

Here is a ugly Python one-liner using lambda.
Use Python 3.8

cleanString = lambda s,countPound=0 : ''.join(filter(lambda char : not isinstance(char, int), [(countPound := countPound + 1) if c == '#' else c if countPound == 0 else (countPound := countPound - 1) for c in s[::-1]]))[::-1]

print(cleanString("Thee# Empires# SS#tateBuildingg#")) # The Empire StateBuilding
print(cleanString("abc#d##c")) # ac
print(cleanString("abc#def##ghi###")) # abd
print(cleanString("abc##d######")) # empty string
print(cleanString("#######")) # empty string
print(cleanString("abc#de##c")) # abc
print(cleanString("abc####dhh##c#")) # d
print(cleanString("abcdef")) # abcdef
print(cleanString("########c")) # c

Idea is based on

def cleanString(s):
    countPound = 0
    ans = ""
    for c in s[::-1]:
        if c == '#':
            countPound += 1
        else:
            if countPound == 0:
                ans += c
            else:
                countPound -= 1
    return ans[::-1]
 

PHP:

function cleanString(string $text)
{
    $result = '';
    for ($i = 0; $i < strlen($text); $i++){
        if($text[$i] === '#') {
            if(strlen($result) > 0) {
                $result = substr($result, 0, -1);
            }
        } else {
            $result .= $text[$i];
        }
    }
    return $result;
}
 

Another JS solution

const cleanString = string => string.split('').reduce((a,v)=> v==="#" ? a.substr(0,a.length-1) : a+=v,'');
 

TypeScript

function cleanString(input: string): string {
  return [...input].reduce(
    (total, cur) => (cur === '#' ? (total = total.slice(0, -1)) : (total += cur)),
    ''
  );
}
 
intN state = 0
for(intN i = 0; i < length; i++)
 if(state == 0)
  if(src[i] == '#')
   state--;
   if(i - state < 0) error....
  else
   state++;

etc, figure it out yourself. It'll take me < 1 hour but I ceil and I charge $1000 an hour.