DEV Community

loading...

Daily Challenge #1 - String Peeler

thepracticaldev profile image dev.to staff ・1 min read

Hey, everyone. We've decided to host a daily challenge series. We'll have a variety of challenges, ranging in difficulty and complexity. If you choose to accept the task, your goal is to write the most efficient function you can for your language. Bonus points for any features you add!

I’ll start you off with a simple, straightforward challenge. Our first one comes from user @SteadyX on CodeWars.

Your goal is to create a function that removes the first and last letters of a string. Strings with two characters or less are considered invalid. You can choose to have your function return null or simply ignore.

The fundamentals are important, it only gets more difficult from here.

Happy coding!


Thank you to CodeWars, who has licensed redistribution of this challenge under the 2-Clause BSD License!

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

Discussion

pic
Editor guide
Collapse
alvaromontoro profile image
Alvaro Montoro

CSS

Just add the class removeFirstAndLastLetter to a tag, and see the first and last letter "removed" from the text 😋

.removeFirstAndLastLetter {
  background: #fff;
  font-family: monospace;
  white-space: nowrap;
  position: relative;
  display: inline-block;
}

.removeFirstAndLastLetter::before,
.removeFirstAndLastLetter::after {
  content: "\00a0";
  background: #fff;
  top: 0;
  display: block;
  position: absolute;
  height: 100%;
  width: auto;
}

.removeFirstAndLastLetter::after {
  right: 0;
}
Enter fullscreen mode Exit fullscreen mode

And as an extra, it can be stylized and animated, so you can see the letters fade out:

Collapse
ben profile image
Ben Halpern

Ha! This one is great.

Collapse
alvaromontoro profile image
Collapse
taillogs profile image
Ryland G

JavaScript

(someString) => someString.length > 2 ? someString.slice(1, -1) : undefined;
Enter fullscreen mode Exit fullscreen mode

Python

someString[1:-1] if len(someString) > 2 else None
Enter fullscreen mode Exit fullscreen mode

C++

someString.size() > 2 ? someString.substr(1, someString.size() - 1) : null;
Enter fullscreen mode Exit fullscreen mode

C

int trimString(char someString[])
{
  if (strlen(someString) > 2) {
    char *copy = malloc((strlen(someString) - 2) * sizeof(char));
    memmove (copy, someString + 1, strlen(someString) - 2);
    printf("%s", copy);
    free(copy);
    return 0;
  }
  return 1;
}
Enter fullscreen mode Exit fullscreen mode
Collapse
rafaacioly profile image
Rafael Acioly

Let people do something 😂

Collapse
jeromedeleon profile image
Jerome De Leon

HAHAHA damn. Let me finish my code LOL.

Collapse
powerc9000 profile image
Clay Murray

Let's just go wild

(someString) => {
   switch(someString.length){
   case 0:
   case 1:
   case 2:
       return null;
   default:
       const arr = someString.split("")
       arr.pop();
       arr.reverse();
       arr.pop();
       arr.reverse();
       return arr.join("")
   }
}

Why not?

Collapse
aybee5 profile image
Ibrahim Abdullahi Aliyu

This is indeed wild

Collapse
alvaromontoro profile image
Alvaro Montoro

In JavaScript it could be 24 bytes:

f=s=>s.slice(1,-1)||null
Collapse
andrewbrown profile image
Andrew Brown 🇨🇦

I am surprised no one wrote test code. Sometimes in interviews with challenge this simple and you have access to run ruby they are expecting to see test code. Check out my ruby test code tutorials buds.

I notice lots of people are raising an error instead of ignoring or returning null so they have failed the challenge's instructions.

require "test/unit"

# remove the first and last letter of a string
# if there is less than 2 characters return zero.
def quartered value
  raise ArgumentError, 'Argument is not a string' unless value.is_a? String
  return value unless value.size > 2
  value[0] = ''
  value.chop
end


class QaurteredTest < Test::Unit::TestCase
  def test_quartered
    assert_equal 'orl', quartered('world'), "quartered('world') should return a string called 'orl'"
  end

  def test_quartered_ignore
    assert_equal 'hi', quartered('hi'), "quartered('hi') should return 'hi'"
  end

  def test_quartered_invalid
    assert_raise_message('Argument is not a string', "quartered(2) should raise exception") do
      quartered(2)
    end
  end
end
Collapse
ben profile image
Ben Halpern

Ruby


def remove_first_and_last(string)
  raise "Invalid" if string.size < 3
  string[1..string.size-2]
end
Collapse
databasesponge profile image
MetaDave 🇪🇺

I think you can get away with string[1..-2] there, Ben.

Collapse
v613 profile image
Ceban Dumitru

BASH

if [[ ${#1} > 2 ]]; then
    echo "${1:1:$(($#1-2))}";
else echo "not validated";
fi
Collapse
orenovadia profile image
orenovadia

I was surprised to find that -1 to work as well:

V=abcde
echo "${V:1:-1}"
Collapse
coreyja profile image
Corey Alexander

Rust

fn remove_first_and_last(string: &str) -> &str {
    remove_first_and_last_n_chars(&string, 1)
}

fn remove_first_and_last_n_chars(string: &str, chars_to_remove: usize) -> &str {
    if string.len() <= (2 * chars_to_remove) {
        panic!("Input string too short")
    }
    let start = chars_to_remove;
    let end = string.len() - 1 - chars_to_remove;

    &string[start..end]
} 

fn main() {
    println!("Ans: {}", remove_first_and_last("Hello, world!"));
    println!("Ans: {}", remove_first_and_last_n_chars("Hello, world!", 2));
    println!("Ans: {}", remove_first_and_last_n_chars("aa", 1));
    println!("Ans: {}", remove_first_and_last_n_chars("aa", 2));
}

View it in the Rust Playground here: play.rust-lang.org/?version=stable...

Collapse
overlordex3 profile image
Exequiel Beker

I tried to not use any str function.

char* trimFirstAndLastLetters(char* str)
{
    int index = 1;

    if(str[0] == '\0' || str[1] == '\0') {
        return NULL;
    }

    while(*(str + index) != '\0') {
        *(str + (index - 1)) = *(str + index);
        index++;
    }

    /* Remove last one */
    *(str + (index - 2)) = '\0';
    return str;
}
Collapse
barbaraips profile image
Bárbara Perdigão

I wanted to take my chances with these challenges, but I decided to start from the beginning, so here's my (super) late entry, done in Java :

public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        System.out.println("Type the word:");
        String word = scan.nextLine();

        if (word.length() > 2) {
            System.out.printf("Result: %s%n", word.substring(1, word.length() - 1));
        } else {
            System.out.println("Invalid word.");
        }

}
Enter fullscreen mode Exit fullscreen mode
Collapse
andreasjakof profile image
Andreas Jakof

in C# as Extension-Method

public static string Peel(this string toPeel)
{
    int residual = toPeel.Length -2;
    if (residual < 1) return null;

    return toPeel.SubString(1,residual); //skip the first and take all but the last char
}
Collapse
martyhimmel profile image
Martin Himmel

PHP

function remove_string_ends($str) {
    if (strlen($str) <= 2) {
        return null;
    }
    return substr($str, 1, -1);
}
Collapse
claudioscatoli profile image
Claudio Scatoli

I like that substr trick with the -1, didn't think of that!

How about this one liner?

<?php

function trimThis(string $str)
{
    return (mb_strlen($str) <= 2) ? null : substr($str,1,-1);
}


Use mb_string to support multibyte chars, such as Chinese

Also typehinted the argument, you never know...


This one is even shorter, possible only if the arg is typehinted tho

<?php
function trimThis(string $str) {
    return substr($str,1,-1) ?: null;
}

When the string is shorter than 2, substr returns false;
when the length is 2, substr returns "".

In both cases it's false, the the return is null.


Edit: many typos, I'm on mobile :/

Collapse
coreyja profile image
Corey Alexander

Ruby

Basic

def remove_first_and_last(some_string)
  raise 'Not long enough' unless some_string.length > 2

  some_string[1..-2]
end

Extra

def remove_first_and_last_n_characters(some_string, chars_to_remove: 1)
  raise 'Not long enough' unless some_string.length > (chars_to_remove * 2)

  start_index = chars_to_remove
  end_index = -1 - chars_to_remove
  some_string[start_index..end_index]
end
Collapse
vguleaev profile image
Vladislav Guleaev
function removeChar(str){
 return str.substr(1, str.length - 2)
};
Collapse
johncip profile image
jmc

Clojure:

(defn trim [s]
  (apply str (drop-last (rest s))))
Enter fullscreen mode Exit fullscreen mode
Collapse
lessp profile image
Tom Ekander

ReasonML

let strip = text =>
  String.(
    length(text) > 2
      ? switch (sub(text, 1, length(text) - 2)) {
        | s => Some(s)
        | exception _ => None
        }
      : None
  );

strip("hello"); // Some("ell")
strip("ab"); // None
strip(""); // None
Collapse
kaspermeyer profile image
Kasper Meyer

Ruby solution

require "minitest/autorun"

class WordTrimmer
  def initialize word
    @word = word
  end

  def trim
    @word.length <= 2 ? @word : @word[1..-2]
  end
end

class WordTrimmerTest < MiniTest::Test
  def test_removing_first_and_last_letter
    assert_equal "aspe", WordTrimmer.new("kasper").trim
  end

  def test_ignoring_two_letter_word
    assert_equal "hi", WordTrimmer.new("hi").trim
  end

  def test_ignoring_one_letter_word
    assert_equal "I", WordTrimmer.new("I").trim
  end
end
Collapse
praneetnadkar profile image
Praneet Nadkar

In C#, I would use in built string function Trim()
In my opinion we don't need Substring() here.
Just call :

readedInput.Trim(readedInput[0], readedInput[readedInput.Length - 1])

With 2 length validation:

var trimmed = readedInput.Length > 2 ? readedInput.Trim(readedInput[0], readedInput[readedInput.Length - 1]) : "Invalid" ;
Collapse
andreasjakof profile image
Andreas Jakof

But what if the input would be "aaajldflbbb"?

When using Trim(char[]), all appearances of the characters given to the method at the beginning and at the end, will be removed, leaving "jldfl".

Removes all leading and trailing occurrences of a set of characters specified in an array from the current String object.

Collapse
rafi993 profile image
Rafi

solution in SQL (postgres)

\set str 'hello world'

select (
     case
       when (select length(:'str') > 2) 
        then (select substr(:'str', 2, length(:'str') - 2) ) 
else 'invalid string' end );
Collapse
mwlang profile image
Michael Lang

Ruby Language Version

With specs

def trim value
  value.to_s[1...-1]
end

require "spec"

describe "#trim" do
  it { expect(trim "Foo Bar").to eq "oo Ba"}
  it { expect(trim "Foo").to eq "o"}
  it { expect(trim "Fo").to eq ""}
  it { expect(trim "F").to eq ""}
  it { expect(trim nil).to be_nil}
  it { expect(trim 777).to eq "7"}
end

output

>> rspec debook_ends.rb
......

Finished in 0.00696 seconds (files took 0.15187 seconds to load)
6 examples, 0 failures
Collapse
viniciuscavagnolli profile image
Vinicius Cavagnolli

VB5 / VB6

Function Challenge1(input As String) As String
    If len(input) <= 2 Then
        Challenge1 = Nothing
    Else
        Challenge1 = Mid$(input, 2, len(input) - 2) 
    End If
End Function

Visual Basic .NET

Function Challenge1(input as String)
    Return If(input.Length > 2, Mid(input, 2, len(input) - 2), Nothing)
End Function

C#

string Challenge1(string input) => input.Length > 2 ? input.Substring(1, input.Length - 2) : null;

C# using LINQ (because yes)

string Challenge1(string input) => input.Length > 2 ? string.Concat(input.Skip(1).Take(input.Length - 2)) : null;
Collapse
jasman7799 profile image
Jarod Smith

// "enterprise" solution
function peelString(str = '')
{
  //validate
  if(typeof(str) != 'string')
    throw new Error(`${str}, ${typeof(str)} is not a string`);
  if(str.length <= 2)
    throw new Error(`${str} does not have atleast 3 letters`);

  // process
  return str.substring(1,str.length-1);
}

My "enterprise" solution

Collapse
scrabill profile image
Shannon Crabill

I liked today's challenge so I'm going back to do past ones

def string_peeler(string)
  if string.length > 2
    string.delete(string[0]).delete(string[-1])
  end
end

Returns

string_peeler("hi") => nil 
string_peeler("killer") => "ille" 
string_peeler("BOB") => "O" 
Collapse
rodrigoords profile image
Rodrigo Sene

JAVA

public class Solution {

    public static String getStringCore(String input){
        if(input.length() > 2){
            return input.substring(1, input.length() -1);
        }
        return "invalid input";
    }

    public static void main(String[] arg){
        System.out.println(Solution.getStringCore("let's do it agin"));
    }
}
Collapse
figueroadavid profile image
David Figueroa

Powershell

function Remove-FirstAndLastCharacter {
    param(
        [parameter(Mandatory,ValueFromPipelineByName)]
        [string]$Input
    )
    if ($Input.length -ge 3)
    { 
        return $Input.SubString(1,$Input.Length - 2)
    }
}
Collapse
aaron_stroud profile image
Aaron Stroud

I see a lot of solutions removing characters without checking to see if they're "letters." Here's my JavaScript solution.

// Remove the first and last _letters_ in a string
function removeFirstLastLetters(str) {
  if (str.length < 3) {
    return null;
  }
  else {
    const regex = /[a-zA-Z]/;

    let firstCharIndex = str.search(regex);

    if (firstCharIndex === -1 ) {
      return null;
    }

    else {
      let lastCharIndex = str.length - str.split("").reverse().join("").search(regex);

      return str.slice(0, firstCharIndex) + str.slice(firstCharIndex + 1, lastCharIndex - 1) + str.slice(lastCharIndex, str.length);
    }
  }
}
Collapse
tblanshard profile image
Tallie

My solution using Python and list comprehension :)

def stringPeeler(string_to_peel):
    if len(string_to_peel) > 2:
        return "".join([x for i, x in enumerate(list(string_to_peel)) if (len(string_to_peel) - 1) > i > 0])
    else:
        return None
Collapse
celyes profile image
Ilyes Chouia

PHP:


function removeFirstAndLastLetter($text){
    return substr($text, 1, -1);
}
echo removeFirstAndLastLetter("Oh no, I lost two letters");

// Outputs : h no, I lost two letter


Collapse
peterbunting profile image
Peter Bunting

In F#. Not the most straightforward way to solve this, but I wanted to use the language Array splicing.

let stringToByteArray (s:string)= System.Text.Encoding.ASCII.GetBytes s
let byteArraySplice x y (b: byte[]) = b.[x..y]
let byteArrayToString (b: byte[]) = System.Text.Encoding.ASCII.GetString b

let stringPeeler s = 
    s
    |> stringToByteArray
    |> byteArraySplice 1 (s.Length - 2)
    |> byteArrayToString

printfn "%s" <| stringPeeler "abcdefgh"
printfn "%s" <| stringPeeler "ab"
printfn "%s" <| stringPeeler "a"
Collapse
peterbunting profile image
Peter Bunting

And it turns out that you don't even need to explicitly convert it to an array. F# will let you do splicing on a string. So a much better solution is:

let stringPeeler (s: string) = s.[1..(s.Length - 2)]
Collapse
gypsydave5 profile image
David Wickes

Factor

USING: kernel math sequences ;
IN: dev.to-daily-challenge

: not-first-and-last ( str -- str ) dup length 2 >  [ rest but-last ] [ ] if ;

and some tests

USING: tools.test dev.to-daily-challenge ;
IN: dev.to-daily-challenge.tests

{ "ell" } [ "hello" not-first-and-last ] unit-test
{ "e" } [ "hel" not-first-and-last ] unit-test
{ "ha" } [ "ha" not-first-and-last ] unit-test
{ "" } [ "" not-first-and-last ] unit-test