Determine if a string is collapsible

From Rosetta Code
Task
Determine if a string is collapsible
You are encouraged to solve this task according to the task description, using any language you may know.

Determine if a character string is   collapsible.

And if so,   collapse the string   (by removing   immediately repeated   characters).


If a character string has   immediately repeated   character(s),   the repeated characters are to be deleted (removed),   but not the primary (1st) character(s).


An   immediately repeated   character is any character that is   immediately   followed by an identical character (or characters).   Another word choice could've been   duplicated character,   but that might have ruled out   (to some readers)   triplicated characters   ···   or more.


{This Rosetta Code task was inspired by a newly introduced   (as of around November 2019)   PL/I   BIF:   collapse.}


Examples

In the following character string:


 The better the 4-wheel drive, the further you'll be from help when ya get stuck! 


Only the 2nd   t,   e, and   l   are repeated characters,   indicated by underscores (above),   even though they (those characters) appear elsewhere in the character string.


So, after collapsing the string, the result would be:

 The beter the 4-whel drive, the further you'l be from help when ya get stuck! 



Another example: In the following character string:

 headmistressship 


The "collapsed" string would be:

 headmistreship 


Task

Write a subroutine/function/procedure/routine···   to locate   repeated   characters and   collapse   (delete)   them from the character string.   The character string can be processed from either direction.


Show all output here, on this page:

  •   the   original string and its length
  •   the resultant string and its length
  •   the above strings should be "bracketed" with   <<<   and   >>>   (to delineate blanks)
  •   «««Guillemets may be used instead for "bracketing" for the more artistic programmers,   shown used here»»»


Use (at least) the following five strings,   all strings are length seventy-two (characters, including blanks),   except the 1st string:

 string
 number
        ╔╗
   1    ║╚═══════════════════════════════════════════════════════════════════════╗   ◄■■■■■■  a null string  (length zero)
   2    ║"If I were two-faced, would I be wearing this one?" --- Abraham Lincoln ║
   3    ║..1111111111111111111111111111111111111111111111111111111111111117777888║
   4    ║I never give 'em hell, I just tell the truth, and they think it's hell. ║
   5    ║                                                    --- Harry S Truman  ║   ◄■■■■■■  has many repeated blanks
        ╚════════════════════════════════════════════════════════════════════════╝



Related tasks



AWK[edit]

 
# syntax: GAWK -f DETERMINE_IF_A_STRING_IS_COLLAPSIBLE.AWK
BEGIN {
for (i=1; i<=9; i++) {
for (j=1; j<=i; j++) {
arr[0] = arr[0] i
}
}
arr[++n] = ""
arr[++n] = "\"If I were two-faced, would I be wearing this one?\" --- Abraham Lincoln "
arr[++n] = "..1111111111111111111111111111111111111111111111111111111111111117777888"
arr[++n] = "I never give 'em hell, I just tell the truth, and they think it's hell. "
arr[++n] = " --- Harry S Truman "
arr[++n] = "The better the 4-wheel drive, the further you'll be from help when ya get stuck!"
arr[++n] = "headmistressship"
for (i=0; i<=n; i++) {
main(arr[i])
}
exit(0)
}
function main(str, c,i,new_str,prev_c) {
for (i=1; i<=length(str); i++) {
c = substr(str,i,1)
if (prev_c != c) {
prev_c = c
new_str = new_str c
}
}
printf("old: %2d <<<%s>>>\n",length(str),str)
printf("new: %2d <<<%s>>>\n\n",length(new_str),new_str)
}
 
Output:
old: 45 <<<122333444455555666666777777788888888999999999>>>
new:  9 <<<123456789>>>

old:  0 <<<>>>
new:  0 <<<>>>

old: 72 <<<"If I were two-faced, would I be wearing this one?" --- Abraham Lincoln >>>
new: 70 <<<"If I were two-faced, would I be wearing this one?" - Abraham Lincoln >>>

old: 72 <<<..1111111111111111111111111111111111111111111111111111111111111117777888>>>
new:  4 <<<.178>>>

old: 72 <<<I never give 'em hell, I just tell the truth, and they think it's hell. >>>
new: 69 <<<I never give 'em hel, I just tel the truth, and they think it's hel. >>>

old: 72 <<<                                                    --- Harry S Truman  >>>
new: 17 <<< - Hary S Truman >>>

old: 80 <<<The better the 4-wheel drive, the further you'll be from help when ya get stuck!>>>
new: 77 <<<The beter the 4-whel drive, the further you'l be from help when ya get stuck!>>>

old: 16 <<<headmistressship>>>
new: 14 <<<headmistreship>>>

C[edit]

Identical implementation as in Determine_if_a_string_is_squeezable, as both tasks are very similar. The Lincoln quote contains backslashes to accommodate the double quotes via the command line. strcmpi is not part of the C Standard Library, thus comment out the definition in the code if testing on a system where it is already included.

 
#include<string.h>
#include<stdlib.h>
#include<stdio.h>
 
#define COLLAPSE 0
#define SQUEEZE 1
 
typedef struct charList{
char c;
struct charList *next;
} charList;
 
/*
Implementing strcmpi, the case insensitive string comparator, as it is not part of the C Standard Library.
 
Comment this out if testing on a compiler where it is already defined.
*/

 
int strcmpi(char* str1,char* str2){
int len1 = strlen(str1), len2 = strlen(str2), i;
 
if(len1!=len2){
return 1;
}
 
else{
for(i=0;i<len1;i++){
if((str1[i]>='A'&&str1[i]<='Z')&&(str2[i]>='a'&&str2[i]<='z')&&(str2[i]-65!=str1[i]))
return 1;
else if((str2[i]>='A'&&str2[i]<='Z')&&(str1[i]>='a'&&str1[i]<='z')&&(str1[i]-65!=str2[i]))
return 1;
else if(str1[i]!=str2[i])
return 1;
}
}
 
return 0;
}
 
charList *strToCharList(char* str){
int len = strlen(str),i;
 
charList *list, *iterator, *nextChar;
 
list = (charList*)malloc(sizeof(charList));
list->c = str[0];
list->next = NULL;
 
iterator = list;
 
for(i=1;i<len;i++){
nextChar = (charList*)malloc(sizeof(charList));
nextChar->c = str[i];
nextChar->next = NULL;
 
iterator->next = nextChar;
iterator = nextChar;
}
 
return list;
}
 
char* charListToString(charList* list){
charList* iterator = list;
int count = 0,i;
char* str;
 
while(iterator!=NULL){
count++;
iterator = iterator->next;
}
 
str = (char*)malloc((count+1)*sizeof(char));
iterator = list;
 
for(i=0;i<count;i++){
str[i] = iterator->c;
iterator = iterator->next;
}
 
free(list);
str[i] = '\0';
 
return str;
}
 
char* processString(char str[100],int operation, char squeezeChar){
charList *strList = strToCharList(str),*iterator = strList, *scout;
 
if(operation==SQUEEZE){
while(iterator!=NULL){
if(iterator->c==squeezeChar){
scout = iterator->next;
 
while(scout!=NULL && scout->c==squeezeChar){
iterator->next = scout->next;
scout->next = NULL;
free(scout);
scout = iterator->next;
}
}
iterator = iterator->next;
}
}
 
else{
while(iterator!=NULL && iterator->next!=NULL){
if(iterator->c == (iterator->next)->c){
scout = iterator->next;
squeezeChar = iterator->c;
 
while(scout!=NULL && scout->c==squeezeChar){
iterator->next = scout->next;
scout->next = NULL;
free(scout);
scout = iterator->next;
}
}
iterator = iterator->next;
}
}
 
return charListToString(strList);
}
 
void printResults(char originalString[100], char finalString[100], int operation, char squeezeChar){
if(operation==SQUEEZE){
printf("Specified Operation : SQUEEZE\nTarget Character : %c",squeezeChar);
}
 
else
printf("Specified Operation : COLLAPSE");
 
printf("\nOriginal %c%c%c%s%c%c%c\nLength : %d",174,174,174,originalString,175,175,175,(int)strlen(originalString));
printf("\nFinal  %c%c%c%s%c%c%c\nLength : %d\n",174,174,174,finalString,175,175,175,(int)strlen(finalString));
}
 
int main(int argc, char** argv){
int operation;
char squeezeChar;
 
if(argc<3||argc>4){
printf("Usage : %s <SQUEEZE|COLLAPSE> <String to be processed> <Character to be squeezed, if operation is SQUEEZE>\n",argv[0]);
return 0;
}
 
if(strcmpi(argv[1],"SQUEEZE")==0 && argc!=4){
scanf("Please enter characted to be squeezed : %c",&squeezeChar);
operation = SQUEEZE;
}
 
else if(argc==4){
operation = SQUEEZE;
squeezeChar = argv[3][0];
}
 
else if(strcmpi(argv[1],"COLLAPSE")==0){
operation = COLLAPSE;
}
 
if(strlen(argv[2])<2){
printResults(argv[2],argv[2],operation,squeezeChar);
}
 
else{
printResults(argv[2],processString(argv[2],operation,squeezeChar),operation,squeezeChar);
}
 
return 0;
}
 

Output :

C:\My Projects\networks>a collapse "The better the 4-wheel drive, the further you'll be from help when ya get stuck!"
Specified Operation : COLLAPSE
Original «««The better the 4-wheel drive, the further you'll be from help when ya get stuck!»»»
Length : 80
Final    «««The beter the 4-whel drive, the further you'l be from help when ya get stuck!»»»
Length : 77

C:\My Projects\networks>a collapse headmistressship
Specified Operation : COLLAPSE
Original «««headmistressship»»»
Length : 16
Final    «««headmistreship»»»
Length : 14

C:\My Projects\networks>a collapse ""
Specified Operation : COLLAPSE
Original «««»»»
Length : 0
Final    «««»»»
Length : 0

C:\My Projects\networks>a collapse "\"If I were two-faced, would I be wearing this one?\" --- Abraham Lincoln"
Specified Operation : COLLAPSE
Original «««"If I were two-faced, would I be wearing this one?" --- Abraham Lincoln»»»
Length : 71
Final    «««"If I were two-faced, would I be wearing this one?" - Abraham Lincoln»»»
Length : 69

C:\My Projects\networks>a collapse ..1111111111111111111111111111111111111111111111111111111111111117777888
Specified Operation : COLLAPSE
Original «««..1111111111111111111111111111111111111111111111111111111111111117777888»»»
Length : 72
Final    «««.178»»»
Length : 4

C:\My Projects\networks>a collapse "I never give 'em hell, I just tell the truth, and they think it's hell."
Specified Operation : COLLAPSE
Original «««I never give 'em hell, I just tell the truth, and they think it's hell.»»»
Length : 71
Final    «««I never give 'em hel, I just tel the truth, and they think it's hel.»»»
Length : 68

C:\My Projects\networks>a collapse "                                                    --- Harry S Truman"
Specified Operation : COLLAPSE
Original «««                                                    --- Harry S Truman»»»
Length : 70
Final    ««« - Hary S Truman»»»
Length : 16

Factor[edit]

USING: formatting io kernel sbufs sequences strings ;
IN: rosetta-code.string-collapse
 
: (collapse) ( str -- str )
unclip-slice 1string >sbuf
[ over last over = [ drop ] [ suffix! ] if ] reduce >string ;
 
: collapse ( str -- str ) [ "" ] [ (collapse) ] if-empty ;
 
: .str ( str -- ) dup length "«««%s»»» (length %d)\n" printf ;
 
: show-collapse ( str -- )
[ "Before collapse: " write .str ]
[ "After collapse: " write collapse .str ] bi nl ;
 
: collapse-demo ( -- )
{
""
"\"If I were two-faced, would I be wearing this one?\" --- Abraham Lincoln "
"..1111111111111111111111111111111111111111111111111111111111111117777888"
"I never give 'em hell, I just tell the truth, and they think it's hell. "
" --- Harry S Truman "
"The better the 4-wheel drive, the further you'll be from help when ya get stuck!"
"headmistressship"
"aardvark"
"😍😀🙌💃😍😍😍🙌"
} [ show-collapse ] each ;
 
MAIN: collapse-demo
Output:

(Using some extra test cases from the Go entry.)

Before collapse: «««»»» (length 0)
After  collapse: «««»»» (length 0)

Before collapse: «««"If I were two-faced, would I be wearing this one?" --- Abraham Lincoln »»» (length 72)
After  collapse: «««"If I were two-faced, would I be wearing this one?" - Abraham Lincoln »»» (length 70)

Before collapse: «««..1111111111111111111111111111111111111111111111111111111111111117777888»»» (length 72)
After  collapse: «««.178»»» (length 4)

Before collapse: «««I never give 'em hell, I just tell the truth, and they think it's hell. »»» (length 72)
After  collapse: «««I never give 'em hel, I just tel the truth, and they think it's hel. »»» (length 69)

Before collapse: «««                                                   ---  Harry S Truman  »»» (length 72)
After  collapse: ««« - Hary S Truman »»» (length 17)

Before collapse: «««The better the 4-wheel drive, the further you'll be from help when ya get stuck!»»» (length 80)
After  collapse: «««The beter the 4-whel drive, the further you'l be from help when ya get stuck!»»» (length 77)

Before collapse: «««headmistressship»»» (length 16)
After  collapse: «««headmistreship»»» (length 14)

Before collapse: «««aardvark»»» (length 8)
After  collapse: «««ardvark»»» (length 7)

Before collapse: «««😍😀🙌💃😍😍😍🙌»»» (length 8)
After  collapse: «««😍😀🙌💃😍🙌»»» (length 6)

Go[edit]

package main
 
import "fmt"
 
// Returns collapsed string, original and new lengths in
// unicode code points (not normalized).
func collapse(s string) (string, int, int) {
r := []rune(s)
le, del := len(r), 0
for i := le - 2; i >= 0; i-- {
if r[i] == r[i+1] {
copy(r[i:], r[i+1:])
del++
}
}
if del == 0 {
return s, le, le
}
r = r[:le-del]
return string(r), le, len(r)
}
 
func main() {
strings:= []string {
"",
`"If I were two-faced, would I be wearing this one?" --- Abraham Lincoln `,
"..1111111111111111111111111111111111111111111111111111111111111117777888",
"I never give 'em hell, I just tell the truth, and they think it's hell. ",
" --- Harry S Truman ",
"The better the 4-wheel drive, the further you'll be from help when ya get stuck!",
"headmistressship",
"aardvark",
"😍😀🙌💃😍😍😍🙌",
}
for _, s := range strings {
cs, olen, clen := collapse(s)
fmt.Printf("original : length = %2d, string = «««%s»»»\n", olen, s)
fmt.Printf("collapsed: length = %2d, string = «««%s»»»\n\n", clen, cs)
}
}
Output:
original : length =  0, string = «««»»»
collapsed: length =  0, string = «««»»»

original : length = 72, string = «««"If I were two-faced, would I be wearing this one?" --- Abraham Lincoln »»»
collapsed: length = 70, string = «««"If I were two-faced, would I be wearing this one?" - Abraham Lincoln »»»

original : length = 72, string = «««..1111111111111111111111111111111111111111111111111111111111111117777888»»»
collapsed: length =  4, string = «««.178»»»

original : length = 72, string = «««I never give 'em hell, I just tell the truth, and they think it's hell. »»»
collapsed: length = 69, string = «««I never give 'em hel, I just tel the truth, and they think it's hel. »»»

original : length = 72, string = «««                                                   ---  Harry S Truman  »»»
collapsed: length = 17, string = ««« - Hary S Truman »»»

original : length = 80, string = «««The better the 4-wheel drive, the further you'll be from help when ya get stuck!»»»
collapsed: length = 77, string = «««The beter the 4-whel drive, the further you'l be from help when ya get stuck!»»»

original : length = 16, string = «««headmistressship»»»
collapsed: length = 14, string = «««headmistreship»»»

original : length =  8, string = «««aardvark»»»
collapsed: length =  7, string = «««ardvark»»»

original : length =  8, string = «««😍😀🙌💃😍😍😍🙌»»»
collapsed: length =  6, string = «««😍😀🙌💃😍🙌»»»

Julia[edit]

const teststrings = [
"",
""""If I were two-faced, would I be wearing this one?" --- Abraham Lincoln """,
"..1111111111111111111111111111111111111111111111111111111111111117777888",
"""I never give 'em hell, I just tell the truth, and they think it's hell. """,
" --- Harry S Truman "]
 
function collapse(s)
len = length(s)
if len < 2
return s, len, s, len
end
result = last = s[1]
for c in s[2:end]
if c != last
last = c
result *= c
end
end
return s, len, result, length(result)
end
 
function testcollapse(arr)
for s in arr
(s1, len1, s2, len2) = collapse(s)
println("«««$s1»»» (length $len1)\n collapses to:\n«««$s2»»» (length $len2).\n")
end
end
 
testcollapse(teststrings)
 
Output:
«««»»» (length 0)
    collapses to:
«««»»» (length 0).

«««"If I were two-faced, would I be wearing this one?" --- Abraham Lincoln »»» (length 72)
    collapses to:
«««"If I were two-faced, would I be wearing this one?" - Abraham Lincoln »»» (length 70).

«««..1111111111111111111111111111111111111111111111111111111111111117777888»»» (length 72)
    collapses to:
«««.178»»» (length 4).

«««I never give 'em hell, I just tell the truth, and they think it's hell. »»» (length 72)
    collapses to:
«««I never give 'em hel, I just tel the truth, and they think it's hel. »»» (length 69).

«««                                                    --- Harry S Truman  »»» (length 72)
    collapses to:
««« - Hary S Truman »»» (length 17).

Condensed version:[edit]

const teststrings = [
"",
""""If I were two-faced, would I be wearing this one?" --- Abraham Lincoln """,
"..1111111111111111111111111111111111111111111111111111111111111117777888",
"""I never give 'em hell, I just tell the truth, and they think it's hell. """,
" --- Harry S Truman "]
 
collapse(s) = (t = isempty(s) ? "" : s[1:1]; for c in s if c != t[end] t *= c end; end; t)
 
for s in teststrings
n, t = length(s), collapse(s)
println("«««$s»»» (length $n)\n collapses to:\n«««$t»»» (length $(length(t))).\n")
end
 

Perl[edit]

use strict;
use warnings;
use utf8;
binmode STDOUT, ":utf8";
 
my @lines = split "\n", <<~'STRINGS';
 
"If I were two-faced, would I be wearing this one?" --- Abraham Lincoln
..1111111111111111111111111111111111111111111111111111111111111117777888
I never give 'em hell, I just tell the truth, and they think it's hell.
--- Harry S Truman
The American people have a right to know if their president is a crook.
--- Richard Nixon
AАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑ
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
STRINGS
 
for (@lines) {
my $squish = s/(.)\1+/$1/gr;
printf "\nLength: %2d <<<%s>>>\nCollapsible: %s\nLength: %2d <<<%s>>>\n",
length($_), $_, $_ ne $squish ? 'True' : 'False', length($squish), $squish
}
Output:
Length:  0 <<<>>>
Collapsible: False
Length:  0 <<<>>>

Length: 72 <<<"If I were two-faced, would I be wearing this one?" --- Abraham Lincoln >>>
Collapsible: True
Length: 70 <<<"If I were two-faced, would I be wearing this one?" - Abraham Lincoln >>>

Length: 72 <<<..1111111111111111111111111111111111111111111111111111111111111117777888>>>
Collapsible: True
Length:  4 <<<.178>>>

Length: 72 <<<I never give 'em hell, I just tell the truth, and they think it's hell. >>>
Collapsible: True
Length: 69 <<<I never give 'em hel, I just tel the truth, and they think it's hel. >>>

Length: 72 <<<                                                    --- Harry S Truman  >>>
Collapsible: True
Length: 17 <<< - Hary S Truman >>>

Length: 72 <<<The American people have a right to know if their president is a crook. >>>
Collapsible: True
Length: 71 <<<The American people have a right to know if their president is a crok. >>>

Length: 72 <<<                                                    --- Richard Nixon   >>>
Collapsible: True
Length: 17 <<< - Richard Nixon >>>

Length: 120 <<<AАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑ>>>
Collapsible: False
Length: 120 <<<AАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑ>>>

Length: 72 <<<AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA>>>
Collapsible: True
Length:  1 <<<A>>>

Perl 6[edit]

Works with: Rakudo version 2019.07.1

Technically, the task is asking for a boolean. "Determine if a string is collapsible" is answerable with True/False, so return a boolean as well.

map {
my $squish = .comb.squish.join;
printf "\nLength: %2d <<<%s>>>\nCollapsible: %s\nLength: %2d <<<%s>>>\n",
.chars, $_, .chars != $squish.chars, $squish.chars, $squish
}, lines
 
q:to/STRINGS/;
 
"If I were two-faced, would I be wearing this one?" --- Abraham Lincoln
..1111111111111111111111111111111111111111111111111111111111111117777888
I never give 'em hell, I just tell the truth, and they think it's hell.
--- Harry S Truman
The American people have a right to know if their president is a crook.
--- Richard Nixon
AАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑ
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
STRINGS
 
Output:
Length:  0 <<<>>>
Collapsible: False
Length:  0 <<<>>>

Length: 72 <<<"If I were two-faced, would I be wearing this one?" --- Abraham Lincoln >>>
Collapsible: True
Length: 70 <<<"If I were two-faced, would I be wearing this one?" - Abraham Lincoln >>>

Length: 72 <<<..1111111111111111111111111111111111111111111111111111111111111117777888>>>
Collapsible: True
Length:  4 <<<.178>>>

Length: 72 <<<I never give 'em hell, I just tell the truth, and they think it's hell. >>>
Collapsible: True
Length: 69 <<<I never give 'em hel, I just tel the truth, and they think it's hel. >>>

Length: 72 <<<                                                    --- Harry S Truman  >>>
Collapsible: True
Length: 17 <<< - Hary S Truman >>>

Length: 72 <<<The American people have a right to know if their president is a crook. >>>
Collapsible: True
Length: 71 <<<The American people have a right to know if their president is a crok. >>>

Length: 72 <<<                                                    --- Richard Nixon   >>>
Collapsible: True
Length: 17 <<< - Richard Nixon >>>

Length: 72 <<<AАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑ>>>
Collapsible: False
Length: 72 <<<AАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑAАΑ>>>

Length: 72 <<<AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA>>>
Collapsible: True
Length:  1 <<<A>>>

Phix[edit]

There is already a builtin we can abuse for this. The documentation of unique() [added for 0.8.1] states:
`If "PRESORTED" is specified, but s is not actually sorted, then only adjacent duplicates are removed.`
If you don't have builtins/punique.e to hand, you may want to take a quick look at squeeze() in [[1]], but obviously w/o ch.

constant tests = {"",
`"If I were two-faced, would I be wearing this one?" --- Abraham Lincoln `,
"..1111111111111111111111111111111111111111111111111111111111111117777888",
"I never give 'em hell, I just tell the truth, and they think it's hell. ",
" --- Harry S Truman "},
fmt = """
length %2d input: <<<%s>>>
length %2d output: <<<%s>>>
"""
for i=1 to length(tests) do
string ti = tests[i], ci = unique(ti, "PRESORTED")
printf(1,fmt,{length(ti),ti,length(ci),ci})
end for
Output:
length  0  input: <<<>>>
length  0 output: <<<>>>

length 72  input: <<<"If I were two-faced, would I be wearing this one?" --- Abraham Lincoln >>>
length 70 output: <<<"If I were two-faced, would I be wearing this one?" - Abraham Lincoln >>>

length 72  input: <<<..1111111111111111111111111111111111111111111111111111111111111117777888>>>
length  4 output: <<<.178>>>

length 72  input: <<<I never give 'em hell, I just tell the truth, and they think it's hell. >>>
length 69 output: <<<I never give 'em hel, I just tel the truth, and they think it's hel. >>>

length 72  input: <<<                                                    --- Harry S Truman  >>>
length 17 output: <<< - Hary S Truman >>>


Python[edit]

from itertools import groupby
 
def collapser(txt):
return ''.join(item for item, grp in groupby(txt))
 
if __name__ == '__main__':
strings = [
"",
'"If I were two-faced, would I be wearing this one?" --- Abraham Lincoln ',
"..1111111111111111111111111111111111111111111111111111111111111117777888",
"I never give 'em hell, I just tell the truth, and they think it's hell. ",
" --- Harry S Truman ",
"The better the 4-wheel drive, the further you'll be from help when ya get stuck!",
"headmistressship",
"aardvark",
"😍😀🙌💃😍😍😍🙌",
]
for txt in strings:
this = "Original"
print(f"\n{this:14} Size: {len(txt)} «««{txt}»»»" )
this = "Collapsed"
sqz = collapser(txt)
print(f"{this:>14} Size: {len(sqz)} «««{sqz}»»»" )
Output:
Original       Size: 0 «««»»»
     Collapsed Size: 0 «««»»»

Original       Size: 72 «««"If I were two-faced, would I be wearing this one?" --- Abraham Lincoln »»»
     Collapsed Size: 70 «««"If I were two-faced, would I be wearing this one?" - Abraham Lincoln »»»

Original       Size: 72 «««..1111111111111111111111111111111111111111111111111111111111111117777888»»»
     Collapsed Size: 4 «««.178»»»

Original       Size: 72 «««I never give 'em hell, I just tell the truth, and they think it's hell. »»»
     Collapsed Size: 69 «««I never give 'em hel, I just tel the truth, and they think it's hel. »»»

Original       Size: 72 «««                                                   ---  Harry S Truman  »»»
     Collapsed Size: 17 ««« - Hary S Truman »»»

Original       Size: 80 «««The better the 4-wheel drive, the further you'll be from help when ya get stuck!»»»
     Collapsed Size: 77 «««The beter the 4-whel drive, the further you'l be from help when ya get stuck!»»»

Original       Size: 16 «««headmistressship»»»
     Collapsed Size: 14 «««headmistreship»»»

Original       Size: 8 «««aardvark»»»
     Collapsed Size: 7 «««ardvark»»»

Original       Size: 8 «««😍😀🙌💃😍😍😍🙌»»»
     Collapsed Size: 6 «««😍😀🙌💃😍🙌»»»

REXX[edit]

/*REXX program "collapses" all immediately repeated characters in a string (or strings).*/
@.= /*define a default for the @. array. */
parse arg x /*obtain optional argument from the CL.*/
if x\='' then @.1= x /*if user specified an arg, use that. */
else do; @.1=
@.2= '"If I were two-faced, would I be wearing this one?" --- Abraham Lincoln '
@.3= ..1111111111111111111111111111111111111111111111111111111111111117777888
@.4= "I never give 'em hell, I just tell the truth, and they think it's hell. "
@.5= ' --- Harry S Truman '
end
 
do j=1; L= length(@.j) /*obtain the length of an array element*/
say copies('═', 105) /*show a separator line between outputs*/
if j>1 & L==0 then leave /*if arg is null and J>1, then leave. */
say ' length='right(L, 3) " input=«««" || @.j || '»»»'
new= collapse(@.j)
w= length(new)
say ' length='right(w, 3) " output=«««" || new || '»»»'
end /*j*/
exit /*stick a fork in it, we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
collapse: procedure; parse arg y 1 $ 2 /*get a value from arg; get 1st char. */
do k=2 to length(y) /*traipse through almost all the chars.*/
_= substr(y, k, 1) /*pick a character from Y*/
if _==right($, 1) then iterate /*Same character? Skip it.*/
$= $ || _ /*append char., it's diff.*/
end /*j*/
return $
output   when using the internal default inputs:
═════════════════════════════════════════════════════════════════════════════════════════════════════════
    length=  0    input=«««»»»
    length=  0   output=«««»»»
═════════════════════════════════════════════════════════════════════════════════════════════════════════
    length= 72    input=«««"If I were two-faced, would I be wearing this one?" --- Abraham Lincoln »»»
    length= 70   output=«««"If I were two-faced, would I be wearing this one?" - Abraham Lincoln »»»
═════════════════════════════════════════════════════════════════════════════════════════════════════════
    length= 72    input=«««..1111111111111111111111111111111111111111111111111111111111111117777888»»»
    length=  4   output=«««.178»»»
═════════════════════════════════════════════════════════════════════════════════════════════════════════
    length= 72    input=«««I never give 'em hell, I just tell the truth, and they think it's hell. »»»
    length= 69   output=«««I never give 'em hel, I just tel the truth, and they think it's hel. »»»
═════════════════════════════════════════════════════════════════════════════════════════════════════════
    length= 72    input=«««                                                   ---  Harry S Truman  »»»
    length= 17   output=««« - Hary S Truman »»»
═════════════════════════════════════════════════════════════════════════════════════════════════════════

Rust[edit]

fn collapse_string(val: &str) -> String {
let mut output = String::new();
let mut chars = val.chars().peekable();
 
while let Some(c) = chars.next() {
while let Some(&b) = chars.peek() {
if b == c {
chars.next();
} else {
break;
}
}
 
output.push(c);
}
 
output
}
 
fn main() {
let tests = [
"122333444455555666666777777788888888999999999",
"",
"\"If I were two-faced, would I be wearing this one?\" --- Abraham Lincoln ",
"..1111111111111111111111111111111111111111111111111111111111111117777888",
"I never give 'em hell, I just tell the truth, and they think it's hell. ",
" --- Harry S Truman ",
"The better the 4-wheel drive, the further you'll be from help when ya get stuck!",
"headmistressship",
];
 
for s in &tests {
println!("Old: {:>3} <<<{}>>>", s.len(), s);
let collapsed = collapse_string(s);
println!("New: {:>3} <<<{}>>>", collapsed.len(), collapsed);
 
println!();
}
}
Output:
Old:  45 <<<122333444455555666666777777788888888999999999>>>
New:   9 <<<123456789>>>

Old:   0 <<<>>>
New:   0 <<<>>>

Old:  72 <<<"If I were two-faced, would I be wearing this one?" --- Abraham Lincoln >>>
New:  70 <<<"If I were two-faced, would I be wearing this one?" - Abraham Lincoln >>>

Old:  72 <<<..1111111111111111111111111111111111111111111111111111111111111117777888>>>
New:   4 <<<.178>>>

Old:  72 <<<I never give 'em hell, I just tell the truth, and they think it's hell. >>>
New:  69 <<<I never give 'em hel, I just tel the truth, and they think it's hel. >>>

Old:  72 <<<                                                    --- Harry S Truman  >>>
New:  17 <<< - Hary S Truman >>>

Old:  80 <<<The better the 4-wheel drive, the further you'll be from help when ya get stuck!>>>
New:  77 <<<The beter the 4-whel drive, the further you'l be from help when ya get stuck!>>>

Old:  16 <<<headmistressship>>>
New:  14 <<<headmistreship>>>

Scala[edit]

 object CollapsibleString {
 
/**Collapse a string (if possible)*/
def collapseString (s : String) : String = {
var res = s
var isOver = false
var i = 0
if(res.size == 0) res
else while(!isOver){
if(res(i) == res(i+1)){
res = res.take(i) ++ res.drop(i+1)
i-=1
}
i+=1
if(i==res.size-1) isOver = true
}
res
}
 
/**Check if a string is collapsible*/
def isCollapsible (s : String) : Boolean = if(collapseString(s).length == s.length) false else true
 
/**Display results as asked in the task*/
def reportResults (s : String) : String = {
val sCollapsed = collapseString(s)
val originalRes = "ORIGINAL  : length = " + s.length() + ", string = «««" + s + "»»»"
val collapsedRes = "COLLAPSED : length = " + sCollapsed.length() + ", string = «««" + sCollapsed + "»»»"
//In order to avoid useless computations, the function isCollapsible isn't called
if(s.length != sCollapsed.length) originalRes + "\n" + collapsedRes + "\n" + "This string IS collapsible !"
else originalRes + "\n" + collapsedRes + "\n" + "This string is NOT collapsible !"
}
 
 
 
def main(args: Array[String]): Unit = {
println(reportResults(""))
println("------------")
println(reportResults("\"If I were two-faced, would I be wearing this one?\" --- Abraham Lincoln "))
println("------------")
println(reportResults("..1111111111111111111111111111111111111111111111111111111111111117777888"))
println("------------")
println(reportResults("I never give 'em hell, I just tell the truth, and they think it's hell. "))
println("------------")
println(reportResults(" --- Harry S Truman "))
println("------------")
println(reportResults("The better the 4-wheel drive, the further you'll be from help when ya get stuck!"))
println("------------")
println(reportResults("headmistressship"))
println("------------")
println(reportResults("aardvark"))
}
 
 
}
 
Output:
ORIGINAL  : length = 0, string = «««»»»
COLLAPSED : length = 0, string = «««»»»
This string is NOT collapsible !
------------
ORIGINAL  : length = 72, string = «««"If I were two-faced, would I be wearing this one?" --- Abraham Lincoln »»»
COLLAPSED : length = 70, string = «««"If I were two-faced, would I be wearing this one?" - Abraham Lincoln »»»
This string IS collapsible !
------------
ORIGINAL  : length = 72, string = «««..1111111111111111111111111111111111111111111111111111111111111117777888»»»
COLLAPSED : length = 4, string = «««.178»»»
This string IS collapsible !
------------
ORIGINAL  : length = 72, string = «««I never give 'em hell, I just tell the truth, and they think it's hell. »»»
COLLAPSED : length = 69, string = «««I never give 'em hel, I just tel the truth, and they think it's hel. »»»
This string IS collapsible !
------------
ORIGINAL  : length = 72, string = «««                                                    --- Harry S Truman  »»»
COLLAPSED : length = 17, string = ««« - Hary S Truman »»»
This string IS collapsible !
------------
ORIGINAL  : length = 80, string = «««The better the 4-wheel drive, the further you'll be from help when ya get stuck!»»»
COLLAPSED : length = 77, string = «««The beter the 4-whel drive, the further you'l be from help when ya get stuck!»»»
This string IS collapsible !
------------
ORIGINAL  : length = 16, string = «««headmistressship»»»
COLLAPSED : length = 14, string = «««headmistreship»»»
This string IS collapsible !
------------
ORIGINAL  : length = 8, string = «««aardvark»»»
COLLAPSED : length = 7, string = «««ardvark»»»
This string IS collapsible !

Tcl[edit]

Please note the ;# ' comments, there appears to be a syntax hightlighting bug with RC

set test {
{}
{"If I were two-faced, would I be wearing this one?" --- Abraham Lincoln }
{..1111111111111111111111111111111111111111111111111111111111111117777888}
{I never give 'em hell, I just tell the truth, and they think it's hell. } ;# '
{ --- Harry S Truman }
{The better the 4-wheel drive, the further you'll be from help when ya get stuck!} ;# '
{headmistressship}
}
 
foreach {str} $test {
# Uses regexp lookbehind to detect repeated characters
set sub [regsub -all {(.)(\1+)} $str {\1}]
 
# Output
puts [format "Original (length %3d): %s" [string length $str] $str]
puts [format "Subbed (length %3d): %s" [string length $sub] $sub]
puts ----------------------
}
 
Output:
Original (length   0):
Subbed   (length   0):
----------------------
Original (length  72): "If I were two-faced, would I be wearing this one?" --- Abraham Lincoln
Subbed   (length  70): "If I were two-faced, would I be wearing this one?" - Abraham Lincoln
----------------------
Original (length  72): ..1111111111111111111111111111111111111111111111111111111111111117777888
Subbed   (length   4): .178
----------------------
Original (length  72): I never give 'em hell, I just tell the truth, and they think it's hell.
Subbed   (length  69): I never give 'em hel, I just tel the truth, and they think it's hel.
----------------------
Original (length  72):                                                     --- Harry S Truman
Subbed   (length  17):  - Hary S Truman
----------------------
Original (length  80): The better the 4-wheel drive, the further you'll be from help when ya get stuck!
Subbed   (length  77): The beter the 4-whel drive, the further you'l be from help when ya get stuck!
----------------------
Original (length  16): headmistressship
Subbed   (length  14): headmistreship
----------------------

zkl[edit]

fcn collapsible(str){			// no Unicode
sink:=Sink(String);
str.reduce('wrap(c1,c2){ if(c1!=c2) sink.write(c2); c2 },""); // prime with \0
cstr:=sink.close();
return(str.len()!=cstr.len(), cstr);
}
strings:=
0'^
"If I were two-faced, would I be wearing this one?" --- Abraham Lincoln
..1111111111111111111111111111111111111111111111111111111111111117777888
I never give 'em hell, I just tell the truth, and they think it's hell.
--- Harry S Truman
The American people have a right to know if their president is a crook.
--- Richard Nixon
The better the 4-wheel drive, the further you'll be from help when ya get stuck!
headmistressship
aardvark^
.split("\n");
#<<<
 
foreach s in (strings){
println("Before: %3d >>>%s<<<".fmt(s.len(),s));
_,cstr:=collapsible(s);
println("After:  %3d >>>%s<<<\n".fmt(cstr.len(),cstr));
}
Output:
Before:   0 >>><<<
After:    0 >>><<<

Before:  72 >>>"If I were two-faced, would I be wearing this one?" --- Abraham Lincoln <<<
After:   70 >>>"If I were two-faced, would I be wearing this one?" - Abraham Lincoln <<<

Before:  72 >>>..1111111111111111111111111111111111111111111111111111111111111117777888<<<
After:    4 >>>.178<<<

Before:  72 >>>I never give 'em hell, I just tell the truth, and they think it's hell. <<<
After:   69 >>>I never give 'em hel, I just tel the truth, and they think it's hel. <<<

Before:  72 >>>                                                    --- Harry S Truman  <<<
After:   17 >>> - Hary S Truman <<<

Before:  72 >>>The American people have a right to know if their president is a crook. <<<
After:   71 >>>The American people have a right to know if their president is a crok. <<<

Before:  72 >>>                                                    --- Richard Nixon   <<<
After:   17 >>> - Richard Nixon <<<

Before:  80 >>>The better the 4-wheel drive, the further you'll be from help when ya get stuck!<<<
After:   77 >>>The beter the 4-whel drive, the further you'l be from help when ya get stuck!<<<

Before:  16 >>>headmistressship<<<
After:   14 >>>headmistreship<<<

Before:   8 >>>aardvark<<<
After:    7 >>>ardvark<<<