Strip a set of characters from a string

From Rosetta Code
Revision as of 22:10, 7 July 2011 by Sonia (talk | contribs) (Go solution)
Task
Strip a set of characters from a string
You are encouraged to solve this task according to the task description, using any language you may know.

The task is to create a function that strips a set of characters from a string. The function should take two arguments: the first argument being a string to stripped and the second, a string containing the set of characters to be stripped. The returned string should contain the first string, stripped of any characters in the second argument:

<lang pseudocode> print stripchars("She was a soul stripper. She took my heart!","aei") Sh ws soul strppr. Sh took my hrt!</lang>

C

<lang c>#include <string.h>

  1. include <malloc.h>
  2. include <stdio.h>
 /* checks if character exists in list */

int contains( char character, char * list ){

 while( *list ){
   if( character == *list )
     return 1;
   ++ list;
 }
 return 0;

}


 /* removes all chars from string */

char * strip_chars( char * string, char * chars ){

 char * newstr = malloc( strlen( string ) );
 int counter = 0;
 while( *string ){
   if( contains( *string, chars ) != 1 ){
     newstr[ counter ] = *string;
     ++ counter;
   }
   ++ string;
 }
 return newstr;

}


int main( int argc, char ** argv ){

 char * new = strip_chars( "She was a soul stripper. She took my heart!", "aei" );
 printf( "%s\n", new );
 free( new );
 return 0;

}</lang>

Result:

Sh ws  soul strppr. Sh took my hrt!

With table lookup

<lang C>#include <stdio.h>

  1. include <stdlib.h>
  2. include <string.h>

char *strip(char * str, char *pat) { /* char replacement is typically done with lookup tables if * the replacement set can be large: it turns O(m n) into * O(m + n). * If same replacement pattern is going to be applied to many * strings, it's better to build a table beforehand and reuse it. * If charset is big like unicode, table needs to be implemented * more efficiently, say using bit field or hash table -- it * all depends on the application. */ int i = 0, tbl[128] = {0}; while (*pat != '\0') tbl[(int)*(pat++)] = 1;

char *ret = malloc(strlen(str)); do { if (!tbl[(int)*str]) ret[i++] = *str; } while (*(str++) != '\0');

/* assuming realloc is efficient and succeeds; if not, we could * do a two-pass, count first, alloc and strip second */ return realloc(ret, i); }

int main() { char * x = strip("She was a soul stripper. She took my heart!", "aei"); printf(x); free(x);

return 0; }</lang>Output same as above.

C++

Note: this uses a C++0x lambda function <lang cpp>#include <algorithm>

  1. include <iostream>
  2. include <string>

std::string stripchars(std::string str, const std::string &chars) {

   str.erase(
       std::remove_if(str.begin(), str.end(), [&](char c){
           return chars.find(c) != std::string::npos;
       }),
       str.end()
   );
   return str;

}

int main() {

   std::cout << stripchars("She was a soul stripper. She took my heart!", "aei") << '\n';
   return 0;

}</lang> Output:

Sh ws  soul strppr. Sh took my hrt!

Common Lisp

<lang lisp>(defun strip-chars (str chars)

 (remove-if (lambda (ch) (find ch chars)) str))

(strip-chars "She was a soul stripper. She took my heart!" "aei")

=> "Sh ws soul strppr. Sh took my hrt!"

</lang>

D

<lang d>import std.stdio, std.string;

void main() {

   auto s = "She was a soul stripper. She took my heart!";
   auto ss = "Sh ws  soul strppr. Sh took my hrt!";
   assert(s.removechars("aei") == ss);

}</lang>

Go

<lang go>package main

import (

   "fmt"
   "strings"

)

func stripchars(str, chr string) string {

   return strings.Map(func(rune int) int {
       if strings.IndexRune(chr, rune) < 0 {
           return rune
       }
       return -1
   }, str)

}

func main() {

   fmt.Println(stripchars("She was a soul stripper. She took my heart!",
       "aei"))

}</lang> Output:

Sh ws  soul strppr. Sh took my hrt!

Haskell

I decided to make the string the second argument and the characters the first argument, because it is more likely for someone to partially apply the characters to be stripped (making a function that strips certain characters), than the string. <lang haskell>stripChars :: String -> String -> String stripChars = filter . flip notElem</lang>

testing in GHCI:

> stripChars "aei" "She was a soul stripper. She took my heart!"
"Sh ws  soul strppr. Sh took my hrt!"

Icon and Unicon

The following works in both languages: <lang unicon>procedure main(A)

   cs := \A[1] | 'aei'   # argument is set of characters to strip
   every write(stripChars(!&input, cs))  # strip all input lines

end

procedure stripChars(s,cs)

   ns := ""
   s ? while ns ||:= (not pos(0), tab(upto(cs)|0)) do tab(many(cs)))
   return ns

end</lang>

Sample runs:

->strip
She was a soul stripper. She took my heart!
Sh ws  soul strppr. Sh took my hrt!
Aardvarks are ant eaters.
Ardvrks r nt trs.
->strip AEIOUaeiou
Aardvarks are ant eaters.
rdvrks r nt trs.
->

J

Solution:
The dyadic primitive -. (Less) is probably the simplest way to solve this task.

Example Usage: <lang j> 'She was a soul stripper. She took my heart!' -. 'aei' Sh ws soul strppr. Sh took my hrt!</lang>

Objective-C

Works with: Mac OS X version 10.5+
Works with: iOS

<lang objc>@interface NSString (StripCharacters) - (NSString *) stripCharactersInSet: (NSCharacterSet *) chars; @end

@implementation NSString (StripCharacters) - (NSString *) stripCharactersInSet: (NSCharacterSet *) chars {

   return [[self componentsSeparatedByCharactersInSet:chars] componentsJoinedByString:@""];

} @end</lang>

To use: <lang objc> NSString *aString = @"She was a soul stripper. She took my heart!";

   NSCharacterSet* chars = [NSCharacterSet characterSetWithCharactersInString:@"aei"];
   // Display the NSString.
   NSLog(@"%@", [aString stripCharactersInSet:chars]);</lang>

OCaml

<lang ocaml>let stripchars s cs =

 let len = String.length s in
 let res = String.create len in
 let rec aux i j =
   if i >= len then String.sub res 0 j
   else if String.contains cs s.[i] then
     aux (succ i) (j)
   else begin
     res.[j] <- s.[i];
     aux (succ i) (succ j)
   end
 in
 aux 0 0</lang>

testing in the toplevel:

# stripchars "She was a soul stripper. She took my heart!" "aei" ;;
- : string = "Sh ws  soul strppr. Sh took my hrt!"

PARI/GP

GP should not be used for string manipulation. A good solution to this problem would probably involve system("perl -e... <lang parigp>stripchars(s, bad)={

 bad=Set(Vec(Vecsmall(bad)));
 s=Vecsmall(s);
 my(v=[]);
 for(i=1,#s,if(!setsearch(bad,s[i]),v=concat(v,s[i])));
 Strchr(v)

}; stripchars("She was a soul stripper. She took my heart!","aei")</lang>

Perl

Caveat: in this version hyphens in the second argument can be used to specify ranges; if you need to actually strip hyphens, you need to put a backslash before it <lang perl>sub stripchars {

   my ($s, $chars) = @_;
   eval("\$s =~ tr/$chars//d;");
   return $s;

}

print stripchars("She was a soul stripper. She took my heart!", "aei"), "\n";</lang> Output:

Sh ws  soul strppr. Sh took my hrt!

Perl 6

<lang perl6>sub strip_chars ( $s, $chars ) {

   return $s.trans( $chars.comb X=>  );

}

say strip_chars( 'She was a soul stripper. She took my heart!', 'aei' );</lang>

Output:

Sh ws  soul strppr. Sh took my hrt!

PHP

<lang php><?php function stripchars($s, $chars) {

   return str_replace(str_split($chars), "", $s);

}

echo stripchars("She was a soul stripper. She took my heart!", "aei"), "\n"; ?></lang> Output:

Sh ws  soul strppr. Sh took my hrt!

PicoLisp

<lang PicoLisp>(de strDiff (Str1 Str2)

  (pack (diff (chop Str1) (chop Str2))) )</lang>

Output:

: (strDiff "She was a soul stripper. She took my heart!" "aei")
-> "Sh ws  soul strppr. Sh took my hrt!"

PL/I

<lang PL/I> strip_chars: procedure (text, chars) returns (character (100) varying);

  declare text character (*) varying, chars character (*) varying;
  declare out_text character (100);
  declare ch character (1);
  declare (i, j) fixed binary;
  j = 0;
  do i = 1 to length(text);
     ch = substr(text, i, 1);
     if index(chars, ch) = 0 then
        do; j = j + 1; substr(out_text, j, 1) = ch; end;
  end;
  return (substr(out_text, 1, j) );

end strip_chars; </lang>

PureBasic

PureBasic uses a single (for ASCII) or a two-byte (for Unicode) null to signal the end of a string. Nulls are thus excluded from the allowable characters to strip as they can't be included in a PureBasic string. <lang PureBasic>Procedure.s stripChars(source.s, charsToStrip.s)

 Protected i, *ptrChar.Character, length = Len(source), result.s
 *ptrChar = @source
 For i = 1 To length
   If Not FindString(charsToStrip, Chr(*ptrChar\c))
     result + Chr(*ptrChar\c)
   EndIf
   *ptrChar + SizeOf(Character)
 Next
 ProcedureReturn result 

EndProcedure

If OpenConsole()

 PrintN(stripChars("She was a soul stripper. She took my heart!", "aei"))
 
 Print(#CRLF$ + #CRLF$ + "Press ENTER to exit"): Input()
 CloseConsole()

EndIf</lang> Sample output:

Sh ws  soul strppr. Sh took my hrt!

Python

Works with: Python version 2.6+

<lang python>>>> def stripchars(s, chars): ... return s.translate(None, chars) ... >>> stripchars("She was a soul stripper. She took my heart!", "aei") 'Sh ws soul strppr. Sh took my hrt!'</lang>

Works with: Python version 2.x

<lang python>>>> import string >>> def stripchars(s, chars): ... return s.translate(string.maketrans("", ""), chars) ... >>> stripchars("She was a soul stripper. She took my heart!", "aei") 'Sh ws soul strppr. Sh took my hrt!'</lang>

Implemented manually: <lang python>>>> def stripchars(s, chars): ... return "".join(c for c in s if c not in chars) ... >>> stripchars("She was a soul stripper. She took my heart!", "aei") 'Sh ws soul strppr. Sh took my hrt!'</lang>

Ruby

<lang ruby>>> "She was a soul stripper. She took my heart!".delete("aei") => "Sh ws soul strppr. Sh took my hrt!"</lang>

Standard ML

<lang sml>fun stripchars (string, chars) = let

 fun aux c =
   if String.isSubstring (str c) chars then
     ""
   else
     str c

in

 String.translate aux string

end</lang>

testing in the interpreter:

- stripchars ("She was a soul stripper. She took my heart!", "aei") ;
val it = "Sh ws  soul strppr. Sh took my hrt!" : string

Tcl

<lang tcl>proc stripchars {str chars} {

   foreach c [split $chars ""] {set str [string map [list $c ""] $str]}
   return $str

}

set s "She was a soul stripper. She took my heart!" puts [stripchars $s "aei"]</lang>