Split a character string based on change of character: Difference between revisions

From Rosetta Code
Content added Content deleted
m (→‎{{header|Wren}}: Changed to Wren S/H)
 
(47 intermediate revisions by 26 users not shown)
Line 31: Line 31:
{{trans|C++}}
{{trans|C++}}


<lang 11l>F split(input, delim)
<syntaxhighlight lang="11l">F split(input, delim)
V res = ‘’
V res = ‘’
L(ch) input
L(ch) input
Line 39: Line 39:
R res
R res


print(split(‘gHHH5YY++///\’, ‘, ’))</lang>
print(split(‘gHHH5YY++///\’, ‘, ’))</syntaxhighlight>


{{out}}
{{out}}
Line 47: Line 47:


=={{header|8080 Assembly}}==
=={{header|8080 Assembly}}==
<lang 8080asm> org 100h
<syntaxhighlight lang="8080asm"> org 100h
jmp demo
jmp demo
;;; Split the string under DE on changing characters,
;;; Split the string under DE on changing characters,
Line 76: Line 76:
jmp 5
jmp 5
string: db 'gHHH5YY++///',5Ch,'$'
string: db 'gHHH5YY++///',5Ch,'$'
out: equ $</lang>
out: equ $</syntaxhighlight>
{{out}}
{{out}}
<pre>g, HHH, 5, YY, ++, ///, \</pre>
<pre>g, HHH, 5, YY, ++, ///, \</pre>


=={{header|8086 Assembly}}==
=={{header|8086 Assembly}}==
<lang asm> cpu 8086
<syntaxhighlight lang="asm"> cpu 8086
org 100h
org 100h
section .text
section .text
Line 114: Line 114:
string: db 'gHHH5YY++///\$'
string: db 'gHHH5YY++///\$'
section .bss
section .bss
buf: resb 32</lang>
buf: resb 32</syntaxhighlight>
{{out}}
{{out}}
<pre>g, HHH, 5, YY, ++, ///, \</pre>
<pre>g, HHH, 5, YY, ++, ///, \</pre>
Line 120: Line 120:
=={{header|AArch64 Assembly}}==
=={{header|AArch64 Assembly}}==
{{works with|as|Raspberry Pi 3B version Buster 64 bits}}
{{works with|as|Raspberry Pi 3B version Buster 64 bits}}
<syntaxhighlight lang="aarch64 assembly">
<lang AArch64 Assembly>
/* ARM assembly AARCH64 Raspberry PI 3B */
/* ARM assembly AARCH64 Raspberry PI 3B */
/* program splitcar64.s */
/* program splitcar64.s */
Line 219: Line 219:
/* for this file see task include a file in language AArch64 assembly */
/* for this file see task include a file in language AArch64 assembly */
.include "../includeARM64.inc"
.include "../includeARM64.inc"
</syntaxhighlight>
</lang>
{{Output}}<pre> gg, HHH, 5, YY, ++, ///, \ </pre>
{{Output}}<pre> gg, HHH, 5, YY, ++, ///, \ </pre>

=={{header|Action!}}==
<syntaxhighlight lang="action!">PROC Split(CHAR ARRAY s)
BYTE i
CHAR curr,last

i=1 last=s(1)
Put('")
WHILE i<=s(0)
DO
curr=s(i)
IF curr#last THEN
Print(", ")
FI
Put(curr)
last=curr
i==+1
OD
Put('")
RETURN

PROC Test(CHAR ARRAY s)
PrintF("Input: ""%S""%E",s)
Print("Split: ") Split(s)
PutE() PutE()
RETURN

PROC Main()
Test("gHHH5YY++///\")
Test("gHHH 5++,,,///\")
RETURN</syntaxhighlight>
{{out}}
[https://gitlab.com/amarok8bit/action-rosetta-code/-/raw/master/images/Split_a_character_string_based_on_change_of_character.png Screenshot from Atari 8-bit computer]
<pre>
Input: "gHHH5YY++///\"
Split: "g, HHH, 5, YY, ++, ///, \"

Input: "gHHH 5++,,,///\"
Split: "g, HHH, , 5, ++, ,,,, ///, \"
</pre>


=={{header|Ada}}==
=={{header|Ada}}==
<lang ada>
<syntaxhighlight lang="ada">
with Ada.Text_IO;
with Ada.Text_IO;
procedure Split is
procedure Split is
Line 240: Line 280:
Print_Tokens ("gHHH5YY+++");
Print_Tokens ("gHHH5YY+++");
end split;
end split;
</syntaxhighlight>
</lang>


=={{header|ALGOL 68}}==
=={{header|ALGOL 68}}==
<syntaxhighlight lang="algol68">BEGIN
{{works with|ALGOL 68G|Any - tested with release 2.8.3.win32}}
<lang algol68>BEGIN
# returns s with ", " added between each change of character #
# returns s with ", " added between each change of character #
PROC split on characters = ( STRING s )STRING:
PROC split on characters = ( STRING s )STRING:
Line 255: Line 294:
[ 3 * ( ( UPB s - LWB s ) + 1 ) ]CHAR result;
[ 3 * ( ( UPB s - LWB s ) + 1 ) ]CHAR result;
INT r pos := LWB result;
INT r pos := LWB result;
INT s pos := LWB s;
CHAR s char := s[ LWB s ];
CHAR s char := s[ LWB s ];
FOR s pos FROM LWB s TO UPB s DO
FOR s pos FROM LWB s TO UPB s DO
Line 273: Line 311:


print( ( split on characters( "gHHH5YY++///\" ), newline ) )
print( ( split on characters( "gHHH5YY++///\" ), newline ) )
END</lang>
END</syntaxhighlight>
{{out}}
{{out}}
<pre>
<pre>
g, HHH, 5, YY, ++, ///, \
g, HHH, 5, YY, ++, ///, \
</pre>

=={{header|Amazing Hopper}}==
VERSION 1: string
<syntaxhighlight lang="c">
#include <basico.h>

#define INICIO 1
#define CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789\"+-/ \\:,;:_*"

algoritmo
objetivo = "gHHH5YY\"\"++ ///,,,\\", indice=0
largo=0, sublargo=0, v=0

#( largo = len(indice:=(onechar(CHARS,objetivo))) )

t=0, nuevo=""
para cada caracter ( v, indice, largo )
#(t = replicate(v, sublargo := ((poschar(INICIO, v, objetivo) - 1 ) ) ))
#(nuevo = cat( cat(nuevo, t), ", "))
objetivo+=sublargo
siguiente
nuevo -= 2
imprimir( "NEW STRING=\n", nuevo,NL)

terminar
</syntaxhighlight>
{{out}}
<pre>
$ hopper3 basica/splitrep.bas
NEW STRING=
g, HHH, 5, YY, "", ++, , ///, ,,,, \
</pre>


VERSION 2: arrays
<syntaxhighlight lang="c">

#include <basico.h>

#define INICIO 1
#define CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789\"+-/ \\:,;:_*"

algoritmo
objetivo = "gHHH5YY\"\"++ ///,,,,\\", indice=0
largo=0, sublargo=0, lista={}, v=0
#( largo = len(indice:=(onechar(CHARS,objetivo))) )

para cada caracter ( v, indice, largo )
#( replicate(v, sublargo := ((poschar(INICIO, v, objetivo) - 1 ))))
meter en( lista )
objetivo+=sublargo
siguiente
imprimir( "LISTA=\n", lista, NL )


terminar
</syntaxhighlight>
{{out}}
<pre>
$ hopper3 basica/splitrep2.bas
LISTA=
g,HHH,5,YY,"",++, ,///,,,,,,\
</pre>
</pre>


=={{header|ANSI BASIC}}==
=={{header|ANSI BASIC}}==
{{works with|Decimal BASIC}}
<lang ansibasic>REM >split
<syntaxhighlight lang="basic">REM >split
DECLARE EXTERNAL FUNCTION FN_split$
DECLARE EXTERNAL FUNCTION FN_split$


Line 298: Line 404:
NEXT i
NEXT i
LET FN_split$ = split$
LET FN_split$ = split$
END FUNCTION</lang>
END FUNCTION</syntaxhighlight>
{{out}}
{{out}}
<pre>g, HHH, 5, YY, ++, ///, \</pre>
<pre>g, HHH, 5, YY, ++, ///, \</pre>
Line 304: Line 410:
=={{header|APL}}==
=={{header|APL}}==
{{works with|Dyalog APL}}
{{works with|Dyalog APL}}
<lang APL>split ← 2↓∘∊(⊂', '),¨(⊢≠¯1⌽⊢)⊂⊢</lang>
<syntaxhighlight lang="apl">split ← 2↓∘∊(⊂', '),¨(⊢≠¯1⌽⊢)⊂⊢</syntaxhighlight>
{{out}}
{{out}}
<pre> split 'gHHH5YY++///\'
<pre> split 'gHHH5YY++///\'
Line 312: Line 418:
===Functional===
===Functional===
{{Trans|JavaScript}}
{{Trans|JavaScript}}
<lang AppleScript>intercalate(", ", ¬
<syntaxhighlight lang="applescript">intercalate(", ", ¬
map(curry(intercalate)'s |λ|(""), ¬
map(curry(intercalate)'s |λ|(""), ¬
group("gHHH5YY++///\\")))
group("gHHH5YY++///\\")))
Line 428: Line 534:
{}
{}
end if
end if
end tail</lang>
end tail</syntaxhighlight>
{{Out}}
{{Out}}
<pre>g, HHH, 5, YY, ++, ///, \</pre>
<pre>g, HHH, 5, YY, ++, ///, \</pre>
Line 434: Line 540:
===Straightforward===
===Straightforward===
(Also case-sensitve.)
(Also case-sensitve.)
<lang applescript>on splitAtCharacterChanges(input)
<syntaxhighlight lang="applescript">on splitAtCharacterChanges(input)
set len to (count input)
set len to (count input)
if (len < 2) then return input
if (len < 2) then return input
Line 457: Line 563:


-- Test code:
-- Test code:
splitAtCharacterChanges("gHHH5YY++///\\")</lang>
splitAtCharacterChanges("gHHH5YY++///\\")</syntaxhighlight>


{{output}}
{{output}}
<lang applescript>"g, HHH, 5, YY, ++, ///, \\"</lang>
<syntaxhighlight lang="applescript">"g, HHH, 5, YY, ++, ///, \\"</syntaxhighlight>


===ASObjC===
===ASObjC===


<lang applescript>use AppleScript version "2.4" -- OS X 10.10 (Yosemite) or later
<syntaxhighlight lang="applescript">use AppleScript version "2.4" -- OS X 10.10 (Yosemite) or later
use framework "Foundation"
use framework "Foundation"


Line 474: Line 580:


-- Test code:
-- Test code:
splitAtCharacterChanges("gHHH5YY++///\\")</lang>
splitAtCharacterChanges("gHHH5YY++///\\")</syntaxhighlight>


{{output}}
{{output}}
<lang applescript>"g, HHH, 5, YY, ++, ///, \\"</lang>
<syntaxhighlight lang="applescript">"g, HHH, 5, YY, ++, ///, \\"</syntaxhighlight>


=={{header|ARM Assembly}}==
=={{header|ARM Assembly}}==
Line 483: Line 589:


{{works with|as|Raspberry Pi}}
{{works with|as|Raspberry Pi}}
<syntaxhighlight lang="arm assembly">
<lang ARM Assembly>
/* ARM assembly Raspberry PI */
/* ARM assembly Raspberry PI */
/* program splitcar.s */
/* program splitcar.s */
Line 601: Line 707:


output : gg, HHH, 5, YY, ++, ///, \
output : gg, HHH, 5, YY, ++, ///, \
</syntaxhighlight>
</lang>


=={{header|Arturo}}==
=={{header|Arturo}}==
<lang rebol>parts: [] current: ""
<syntaxhighlight lang="rebol">parts: [] current: ""
loop split {gHHH5YY++///\} 'ch [
loop split {gHHH5YY++///\} 'ch [
if? or? empty? current
if? or? empty? current
Line 614: Line 720:
]
]
'parts ++ current
'parts ++ current
print parts</lang>
print parts</syntaxhighlight>


{{out}}
{{out}}
Line 621: Line 727:


=={{header|AutoHotkey}}==
=={{header|AutoHotkey}}==
<lang AutoHotkey>Split_Change(str){
<syntaxhighlight lang="autohotkey">Split_Change(str){
for i, v in StrSplit(str)
for i, v in StrSplit(str)
res .= (v=prev) ? v : (res?", " :"") v , prev := v
res .= (v=prev) ? v : (res?", " :"") v , prev := v
return res
return res
}</lang>
}</syntaxhighlight>
Examples:<lang AutoHotkey>str := "gHHH5YY++///\"
Examples:<syntaxhighlight lang="autohotkey">str := "gHHH5YY++///\"
MsgBox % Split_Change(str)</lang>
MsgBox % Split_Change(str)</syntaxhighlight>
Outputs:<pre>g, HHH, 5, YY, ++, ///, \</pre>
Outputs:<pre>g, HHH, 5, YY, ++, ///, \</pre>
===RegEx Version===
===RegEx Version===
<lang AutoHotkey>Split_Change(str){
<syntaxhighlight lang="autohotkey">Split_Change(str){
return RegExReplace(str, "(.)\1*(?!$)", "$0, ")
return RegExReplace(str, "(.)\1*(?!$)", "$0, ")
}</lang>
}</syntaxhighlight>
Examples:<lang AutoHotkey>str := "gHHH5YY++///\"
Examples:<syntaxhighlight lang="autohotkey">str := "gHHH5YY++///\"
MsgBox % Split_Change(str)</lang>
MsgBox % Split_Change(str)</syntaxhighlight>
Outputs:<pre>g, HHH, 5, YY, ++, ///, \</pre>
Outputs:<pre>g, HHH, 5, YY, ++, ///, \</pre>


=={{header|AWK}}==
=={{header|AWK}}==
<syntaxhighlight lang="awk">
<lang AWK>
# syntax: GAWK -f SPLIT_A_CHARACTER_STRING_BASED_ON_CHANGE_OF_CHARACTER.AWK
# syntax: GAWK -f SPLIT_A_CHARACTER_STRING_BASED_ON_CHANGE_OF_CHARACTER.AWK
BEGIN {
BEGIN {
Line 657: Line 763:
return(new_str)
return(new_str)
}
}
</syntaxhighlight>
</lang>
{{out}}
{{out}}
<pre>
<pre>
Line 666: Line 772:
=={{header|BaCon}}==
=={{header|BaCon}}==
Literal strings in BaCon are passed to the C compiler as they are; a backslash therefore needs to be escaped.
Literal strings in BaCon are passed to the C compiler as they are; a backslash therefore needs to be escaped.
<lang freebasic>txt$ = "gHHH5YY++///\\"
<syntaxhighlight lang="freebasic">txt$ = "gHHH5YY++///\\"


c$ = LEFT$(txt$, 1)
c$ = LEFT$(txt$, 1)
Line 677: Line 783:
END IF
END IF
PRINT d$;
PRINT d$;
NEXT</lang>
NEXT</syntaxhighlight>
{{out}}
{{out}}
<pre>
<pre>
g, HHH, 5, YY, ++, ///, \
g, HHH, 5, YY, ++, ///, \
</pre>
</pre>

=={{header|BASIC256}}==
<syntaxhighlight lang="freebasic">function split$(instring$)
if length(instring$) < 2 then return instring$
ret$ = left(instring$,1)
for i = 2 to length(instring$)
if mid(instring$,i,1) <> mid(instring$, i-1, 1) then ret$ += ", "
ret$ += mid(instring$, i, 1)
next i
return ret$
end function

print split$("gHHH5YY++///\")</syntaxhighlight>


=={{header|BBC BASIC}}==
=={{header|BBC BASIC}}==
<lang bbcbasic>REM >split
<syntaxhighlight lang="bbcbasic">REM >split
PRINT FN_split( "gHHH5YY++///\" )
PRINT FN_split( "gHHH5YY++///\" )
END
END
Line 700: Line 819:
split$ += d$
split$ += d$
NEXT
NEXT
= split$</lang>
= split$</syntaxhighlight>
{{out}}
{{out}}
<pre>g, HHH, 5, YY, ++, ///, \</pre>
<pre>g, HHH, 5, YY, ++, ///, \</pre>

=={{header|BQN}}==
<syntaxhighlight lang="bqn">Split ← (+`⊏⊸»⊸≠)⊸⊔
Join ← {∾⟜𝕨⊸∾´𝕩}

", " Join⟜Split "gHHH5YY++///\"</syntaxhighlight>
{{out}}
<pre>"g, HHH, 5, YY, ++, ///, \"</pre>


=={{header|C}}==
=={{header|C}}==
<lang c>#include <stdio.h>
<syntaxhighlight lang="c">#include <stdio.h>
#include <stdlib.h>
#include <stdlib.h>
#include <string.h>
#include <string.h>
Line 728: Line 855:
*(counter--)='\0';
*(counter--)='\0';
return realloc(result,strlen(result));
return realloc(result,strlen(result));
}</lang>
}</syntaxhighlight>
{{out}}
{{out}}
<pre>
<pre>
Line 735: Line 862:


=={{header|C sharp}}==
=={{header|C sharp}}==
<lang csharp>using System;
<syntaxhighlight lang="csharp">using System;
using System.Linq;
using System.Linq;
using System.Collections.Generic;
using System.Collections.Generic;
Line 766: Line 893:


public static string Delimit<T>(this IEnumerable<T> source, string separator = "") => string.Join(separator ?? "", source);
public static string Delimit<T>(this IEnumerable<T> source, string separator = "") => string.Join(separator ?? "", source);
}</lang>
}</syntaxhighlight>
{{out}}
{{out}}
<pre>
<pre>
Line 773: Line 900:


=={{header|C++}}==
=={{header|C++}}==
<lang cpp>
<syntaxhighlight lang="cpp">
// Solution for http://rosettacode.org/wiki/Split_a_character_string_based_on_change_of_character
// Solution for http://rosettacode.org/wiki/Split_a_character_string_based_on_change_of_character
#include<string>
#include<string>
Line 790: Line 917:
int main(){
int main(){
std::cout << split("gHHH5 ))YY++,,,///\\", ", ") << std::endl;
std::cout << split("gHHH5 ))YY++,,,///\\", ", ") << std::endl;
}</lang>
}</syntaxhighlight>
{{out}}
{{out}}
<pre>g, HHH, 5, , )), YY, ++, ,,,, ///, \</pre>
<pre>g, HHH, 5, , )), YY, ++, ,,,, ///, \</pre>


=={{header|Clojure}}==
=={{header|Clojure}}==
<lang clojure>(defn print-cchanges [s]
<syntaxhighlight lang="clojure">(defn print-cchanges [s]
(println (clojure.string/join ", " (map first (re-seq #"(.)\1*" s)))))
(println (clojure.string/join ", " (map first (re-seq #"(.)\1*" s)))))


(print-cchanges "gHHH5YY++///\\")
(print-cchanges "gHHH5YY++///\\")
</syntaxhighlight>
</lang>
{{out}}
{{out}}
<pre>g, HHH, 5, YY, ++, ///, \</pre>
<pre>g, HHH, 5, YY, ++, ///, \</pre>

=={{header|CLU}}==
<syntaxhighlight lang="clu">% Split a string based on a change of character
split_on_change = iter (s: string) yields (string)
part: string := ""
for c: char in string$chars(s) do
if ~string$empty(part)
cand part[string$size(part)] ~= c then
yield(part)
part := ""
end
part := part || string$c2s(c)
end
yield(part)
end split_on_change

start_up = proc ()
po: stream := stream$primary_output()
str: string := "gHHH5YYY++///\\" % \\ escapes, as in C
rslt: string := ""
first: bool := true
for part: string in split_on_change(str) do
if first then first := false
else rslt := rslt || ", "
end
rslt := rslt || part
end
stream$putl(po, rslt)
end start_up</syntaxhighlight>
{{out}}
<pre>g, HHH, 5, YYY, ++, ///, \</pre>


=={{header|COBOL}}==
=={{header|COBOL}}==
<syntaxhighlight lang="cobol">
<lang COBOL>
identification division.
identification division.
program-id. split-ch.
program-id. split-ch.
Line 866: Line 1,025:


end program split-ch.
end program split-ch.
</syntaxhighlight>
</lang>
{{out}}
{{out}}
<pre>
<pre>
Line 880: Line 1,039:
=={{header|Common Lisp}}==
=={{header|Common Lisp}}==


<lang lisp>(defun split (string)
<syntaxhighlight lang="lisp">(defun split (string)
(loop :for prev := nil :then c
(loop :for prev := nil :then c
:for c :across string
:for c :across string
Line 886: Line 1,045:


(split "gHHH5YY++///\\")
(split "gHHH5YY++///\\")
</syntaxhighlight>
</lang>
{{out}}
{{out}}
<pre>g, HHH, 5, YY, ++, ///, \</pre>
<pre>g, HHH, 5, YY, ++, ///, \</pre>
Line 892: Line 1,051:
Doing more work that what's being ask, the following solution builds a list of strings then output it:
Doing more work that what's being ask, the following solution builds a list of strings then output it:


<lang lisp>(defun split (string)
<syntaxhighlight lang="lisp">(defun split (string)
(flet ((make-buffer ()
(flet ((make-buffer ()
(make-array 0 :element-type 'character :adjustable t :fill-pointer t)))
(make-array 0 :element-type 'character :adjustable t :fill-pointer t)))
Line 906: Line 1,065:
(format t "~{~A~^, ~}"(nreverse result)))))
(format t "~{~A~^, ~}"(nreverse result)))))


(split "gHHH5YY++///\\")</lang>
(split "gHHH5YY++///\\")</syntaxhighlight>
{{out}}
{{out}}
<pre>g, HHH, 5, YY, ++, ///, \</pre>
<pre>g, HHH, 5, YY, ++, ///, \</pre>


=={{header|Cowgol}}==
=={{header|Cowgol}}==
<lang cowgol>include "cowgol.coh";
<syntaxhighlight lang="cowgol">include "cowgol.coh";


sub split(in: [uint8], buf: [uint8]): (out: [uint8]) is
sub split(in: [uint8], buf: [uint8]): (out: [uint8]) is
Line 931: Line 1,090:


print(split("gHHH5YY++//\\", &buf[0]));
print(split("gHHH5YY++//\\", &buf[0]));
print_nl();</lang>
print_nl();</syntaxhighlight>
{{out}}
{{out}}
<pre>g, HHH, 5, YY, ++, //, \</pre>
<pre>g, HHH, 5, YY, ++, //, \</pre>
Line 937: Line 1,096:
=={{header|D}}==
=={{header|D}}==


<lang D>import std.stdio;
<syntaxhighlight lang="d">import std.stdio;


void main() {
void main() {
Line 951: Line 1,110:
}
}
writeln();
writeln();
}</lang>
}</syntaxhighlight>


{{output}}
{{output}}
<pre>g, HHH, 5, YY, ++, ///, \</pre>
<pre>g, HHH, 5, YY, ++, ///, \</pre>

=={{header|Delphi}}==
{{works with|Delphi|6.0}}
{{libheader|SysUtils,StdCtrls}}


<syntaxhighlight lang="Delphi">
function SplitStringCharChange(S: string): string;
{Split string whenever the previous char is different from the current one}
var I: integer;
var C: char;
begin
Result:='';
{Copy string to output}
for I:=1 to Length(S) do
begin
Result:=Result+S[I];
{Appended ", " if the next char is different}
if (I<Length(S)) and (S[I]<>S[I+1]) then Result:=Result+', ';
end;
end;


procedure ShowSplitString(Memo: TMemo);
const S1 = 'gHHH5YY++///\';
var S2: string;
begin
Memo.Lines.Add(S1);
S2:=SplitStringCharChange(S1);
Memo.Lines.Add(S2);
end;

</syntaxhighlight>
{{out}}
<pre>
gHHH5YY++///\
g, HHH, 5, YY, ++, ///, \
Elapsed Time: 1.767 ms.

</pre>



=={{header|Dyalect}}==
=={{header|Dyalect}}==


<lang dyalect>func String.smartSplit() {
<syntaxhighlight lang="dyalect">func String.SmartSplit() {
var c
var c
var str = ""
var str = ""
var last = this.len() - 1
var last = this.Length() - 1

for n in 0..last {
for n in 0..last {
if c && this[n] != c {
if c && this[n] != c {
Line 970: Line 1,170:
str += c
str += c
}
}

str
str
}
}

print("gHHH5YY++///\\".smartSplit())</lang>
print("gHHH5YY++///\\".SmartSplit())</syntaxhighlight>


{{out}}
{{out}}
Line 982: Line 1,182:
=={{header|EasyLang}}==
=={{header|EasyLang}}==


<syntaxhighlight lang="text">
<lang>a$ = "gHHH5YY++///\"
a$[] = str_chars a$
a$ = "gHHH5YY++///\\"
c$ = a$[0]
a$[] = strchars a$
for i range len a$[]
cp$ = a$[1]
if a$[i] <> c$
for c$ in a$[]
b$ &= ", "
if c$ <> cp$
c$ = a$[i]
s$ &= ", "
cp$ = c$
.
b$ &= a$[i]
.
s$ &= c$
.
.
print b$</lang>
print s$
</syntaxhighlight>
{{out}}
{{out}}
<pre>
<pre>
Line 999: Line 1,201:


=={{header|Elixir}}==
=={{header|Elixir}}==
<lang elixir>split = fn str ->
<syntaxhighlight lang="elixir">split = fn str ->
IO.puts " input string: #{str}"
IO.puts " input string: #{str}"
String.graphemes(str)
String.graphemes(str)
Line 1,007: Line 1,209:
end
end


split.("gHHH5YY++///\\")</lang>
split.("gHHH5YY++///\\")</syntaxhighlight>


{{out}}
{{out}}
Line 1,016: Line 1,218:


=={{header|F_Sharp|F#}}==
=={{header|F_Sharp|F#}}==
<lang fsharp>open System.Text.RegularExpressions
<syntaxhighlight lang="fsharp">open System.Text.RegularExpressions
let splitRuns s = Regex("""(.)\1*""").Matches(s) |> Seq.cast<Match> |> Seq.map (fun m -> m.Value) |> Seq.toList
let splitRuns s = Regex("""(.)\1*""").Matches(s) |> Seq.cast<Match> |> Seq.map (fun m -> m.Value) |> Seq.toList
printfn "%A" (splitRuns """gHHH5YY++///\""")</lang>
printfn "%A" (splitRuns """gHHH5YY++///\""")</syntaxhighlight>
{{out}}
{{out}}
<pre>["g"; "HHH"; "5"; "YY"; "++"; "///"; "\"]</pre>
<pre>["g"; "HHH"; "5"; "YY"; "++"; "///"; "\"]</pre>


=={{header|Factor}}==
=={{header|Factor}}==
<lang factor>USE: splitting.monotonic
<syntaxhighlight lang="factor">USE: splitting.monotonic
"gHHH5YY++///\\"
"gHHH5YY++///\\"
"aaabbccccdeeff" [ [ = ] monotonic-split ", " join print ] bi@</lang>
"aaabbccccdeeff" [ [ = ] monotonic-split ", " join print ] bi@</syntaxhighlight>
{{out}}
{{out}}
<pre>
<pre>
Line 1,034: Line 1,236:
=={{header|Forth}}==
=={{header|Forth}}==
{{works with|Gforth|0.7.3}}
{{works with|Gforth|0.7.3}}
<lang Forth>CREATE A 0 ,
<syntaxhighlight lang="forth">CREATE A 0 ,
: C@A+ A @ C@ [ 1 CHARS ]L A +! ;
: C@A+ A @ C@ [ 1 CHARS ]L A +! ;
: SPLIT. ( c-addr u --) SWAP A ! A @ C@
: SPLIT. ( c-addr u --) SWAP A ! A @ C@
Line 1,046: Line 1,248:
s" gHHH5YY++///\" TEST
s" gHHH5YY++///\" TEST
s" gHHH5 ))YY++,,,///\" TEST
s" gHHH5 ))YY++,,,///\" TEST
BYE</lang>
BYE</syntaxhighlight>
{{out}}
{{out}}
<pre>input: gHHH5YY++///\
<pre>input: gHHH5YY++///\
Line 1,060: Line 1,262:
If the problem were to be solved by writing a "main line" only, there would have to be a declaration of the text variable there but since a subroutine can receive a CHARACTER variable of any size (the actual size is passed as a secret parameter), this can be dodged.
If the problem were to be solved by writing a "main line" only, there would have to be a declaration of the text variable there but since a subroutine can receive a CHARACTER variable of any size (the actual size is passed as a secret parameter), this can be dodged.


For this example a DO-loop stepping along the text is convenient, but in a larger context it would probably be most useful to work along the text with fingers L1 and L2 marking the start and finish positions of each sequence. <lang Fortran> SUBROUTINE SPLATTER(TEXT) !Print a comma-separated list. Repeated characters constitute one item.
For this example a DO-loop stepping along the text is convenient, but in a larger context it would probably be most useful to work along the text with fingers L1 and L2 marking the start and finish positions of each sequence. <syntaxhighlight lang="fortran"> SUBROUTINE SPLATTER(TEXT) !Print a comma-separated list. Repeated characters constitute one item.
Can't display the inserted commas in a different colour so as not to look like any commas in TEXT.
Can't display the inserted commas in a different colour so as not to look like any commas in TEXT.
CHARACTER*(*) TEXT !The text.
CHARACTER*(*) TEXT !The text.
Line 1,080: Line 1,282:
PROGRAM POKE
PROGRAM POKE
CALL SPLATTER("gHHH5YY++///\") !The example given.
CALL SPLATTER("gHHH5YY++///\") !The example given.
END</lang>
END</syntaxhighlight>
Unfortunately, the syntax highlighter has failed to notice the terminating quote character, presumably because the preceding backslash might be an "escape sequence" trigger, a facility ''not'' used in Fortran text ''literals'' except possibly as a later modernist option.
Unfortunately, the syntax highlighter has failed to notice the terminating quote character, presumably because the preceding backslash might be an "escape sequence" trigger, a facility ''not'' used in Fortran text ''literals'' except possibly as a later modernist option.


Line 1,089: Line 1,291:


=={{header|FreeBASIC}}==
=={{header|FreeBASIC}}==
<lang freebasic>function split( instring as string ) as string
<syntaxhighlight lang="freebasic">function split( instring as string ) as string
if len(instring) < 2 then return instring
if len(instring) < 2 then return instring
dim as string ret = left(instring,1)
dim as string ret = left(instring,1)
Line 1,097: Line 1,299:
next i
next i
return ret
return ret
end function</lang>
end function</syntaxhighlight>

=={{header|Frink}}==
<syntaxhighlight lang="frink">s = "gHHH5YY++///\\"
println[join[", ", map[getFunction["first", 1], s =~ %r/((.)\2*)/g]]]</syntaxhighlight>
{{out}}
<pre>
g, HHH, 5, YY, ++, ///, \
</pre>

=={{header|FutureBasic}}==
FB can process either Pascal strings (slowly being deprecated), or Apple's Core Foundation CFStrings (and Objective-C NSStrings). Here's the old-school Pascal string function:
<syntaxhighlight lang="text">
local fn SplitString( inputStr as Str255 ) as Str255
Str255 resultStr
NSUInteger i

if len$( inputStr ) < 2 then resultStr = inputStr : exit fn
resultStr = left$( inputStr, 1 )
for i = 2 to len$( inputStr )
if mid$( inputStr, i, 1 ) <> mid$( inputStr, i - 1, 1 ) then resultStr = resultStr + ", "
resultStr = resultStr + mid$(inputStr, i, 1)
next
end fn = resultStr

window 1

print fn SplitString( "gHHH5YY++///\" )

HandleEvents
</syntaxhighlight>
And here's the recommended CFString counterpart:
<syntaxhighlight lang="text">
local fn SplitString( inputStr as CFStringRef ) as CFStringRef
NSUInteger i
unichar chr, lastChr = fn StringCharacterAtIndex( inputStr, 0 )
CFMutableStringRef resultStr = fn MutableStringWithCapacity(0)
for i = 0 to len( inputStr ) - 1
chr = fn StringCharacterAtIndex( inputStr, i )
if ( chr != lastChr ) then MutableStringAppendString( resultStr, @", " )
MutableStringAppendString( resultStr, mid( inputStr, i, 1 ) )
lastChr = chr
next
end fn = resultStr

window 1

print fn SplitString( @"gHHH5YY++///\\" )

HandleEvents
</syntaxhighlight>
'''Output for either function:'''
<pre>
g, HHH, 5, YY, ++, ///, \
</pre>


=={{header|Go}}==
=={{header|Go}}==
Treating "character" as a byte:
Treating "character" as a byte:
<lang go>package main
<syntaxhighlight lang="go">package main


import (
import (
Line 1,127: Line 1,384:
}
}
return b.String()
return b.String()
}</lang>
}</syntaxhighlight>
{{out}}
{{out}}
<pre>
<pre>
g, HHH, 5, YY, ++, ///, \
g, HHH, 5, YY, ++, ///, \
</pre>
</pre>



=={{header|Haskell}}==
=={{header|Haskell}}==


<lang Haskell>import Data.List (group, intercalate)
<syntaxhighlight lang="haskell">import Data.List (group, intercalate)


main :: IO ()
main :: IO ()
main = putStrLn $ intercalate ", " (group "gHHH5YY++///\\")</lang>
main = putStrLn $ intercalate ", " (group "gHHH5YY++///\\")</syntaxhighlight>


{{Out}}
<pre>g, HHH, 5, YY, ++, ///, \</pre>

or as a hand-written fold:
<syntaxhighlight lang="haskell">import Data.List (intercalate)
import Data.Bool (bool)

charGroups :: String -> [String]
charGroups =
let go (a, b) (s, groups)
| a == b = (b : s, groups)
| otherwise =
( [a],
bool s [b] (null s) : groups
)
in uncurry (:) . foldr go ([], []) . (zip <*> tail)

main :: IO ()
main =
putStrLn $ intercalate ", " $ charGroups "gHHH5YY++///\\"</syntaxhighlight>
<pre>g, HHH, 5, YY, ++, ///, \</pre>

or in terms of '''span''':
<syntaxhighlight lang="haskell">import Data.List (intercalate)

charGroups :: String -> [String]
charGroups [] = []
charGroups (c : cs) =
let (xs, ys) = span (c ==) cs
in (c : xs) : charGroups ys

main :: IO ()
main =
putStrLn $ intercalate ", " $ charGroups "gHHH5YY++///\\"</syntaxhighlight>
{{Out}}
{{Out}}
<pre>g, HHH, 5, YY, ++, ///, \</pre>
<pre>g, HHH, 5, YY, ++, ///, \</pre>


=={{header|IS-BASIC}}==
=={{header|IS-BASIC}}==
<lang IS-BASIC>100 LET S$="gHHH5YY++///\"
<syntaxhighlight lang="is-basic">100 LET S$="gHHH5YY++///\"
110 PRINT S$(1);
110 PRINT S$(1);
120 FOR I=2 TO LEN(S$)
120 FOR I=2 TO LEN(S$)
Line 1,150: Line 1,442:
140 PRINT S$(I);
140 PRINT S$(I);
150 NEXT
150 NEXT
160 PRINT</lang>
160 PRINT</syntaxhighlight>


=={{header|J}}==
=={{header|J}}==
'''Solution:'''
'''Solution:'''
<lang j>splitChars=: (1 ,~ 2 ~:/\ ]) <;.2 ]
<syntaxhighlight lang="j">splitChars=: (1 ,~ 2 ~:/\ ]) <;.2 ]
delimitChars=: ', ' joinstring splitChars</lang>
delimitChars=: ', ' joinstring splitChars</syntaxhighlight>
'''Example Usage:'''
'''Example Usage:'''
<lang j> delimitChars 'gHHH5YY++///\'
<syntaxhighlight lang="j"> delimitChars 'gHHH5YY++///\'
g, HHH, 5, YY, ++, ///, \</lang>
g, HHH, 5, YY, ++, ///, \</syntaxhighlight>


=={{header|Java}}==
=={{header|Java}}==
You can use a regular expression to capture every character preceded by 0 or more of itself.

<syntaxhighlight lang="java">
<lang Java>package org.rosettacode;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
</syntaxhighlight>
<syntaxhighlight lang="java">
String split(String string) {
Pattern pattern = Pattern.compile("(.)\\1*");
Matcher matcher = pattern.matcher(string);
StringBuilder strings = new StringBuilder();
int index = 0;
while (matcher.find()) {
if (index++ != 0)
strings.append(", ");
strings.append(matcher.group());
}
return strings.toString();
}
</syntaxhighlight>
<pre>
g, HHH, 5, YY, ++, ///, \
</pre>
<br />
An alternate demonstration
<syntaxhighlight lang="java">package org.rosettacode;


import java.util.ArrayList;
import java.util.ArrayList;
Line 1,226: Line 1,541:
return output.toString();
return output.toString();
}
}
}</lang>
}</syntaxhighlight>


{{Out}}
{{Out}}
Line 1,234: Line 1,549:
===ES6===
===ES6===
{{Trans|Haskell}}
{{Trans|Haskell}}
<lang JavaScript>(() => {
<syntaxhighlight lang="javascript">(() => {
"use strict";
"use strict";


Line 1,261: Line 1,576:
xs => 0 < xs.length ? (() => {
xs => 0 < xs.length ? (() => {
const [h, ...t] = xs;
const [h, ...t] = xs;
const [v, r] = t.reduce(
const [groups, g] = t.reduce(
([gs, a], x) => eqOp(x)(a[0]) ? (
([gs, a], x) => eqOp(x)(a[0]) ? (
Tuple(gs)([...a, x])
Tuple(gs)([...a, x])
Line 1,268: Line 1,583:
);
);


return [...v, r];
return [...groups, g];
})() : [];
})() : [];


Line 1,290: Line 1,605:
// MAIN ---
// MAIN ---
return main();
return main();
})();</lang>
})();</syntaxhighlight>
{{Out}}
<pre>g, HHH, 5, YY, ++, ///, \</pre>


Or, in terms of a general `span` function:
<syntaxhighlight lang="javascript">(() => {
"use strict";

// -------- STRING SPLIT ON CHARACTER CHANGES --------

// charGroups :: String -> [String]
const charGroups = s =>
// The characters of s split at each point where
// consecutive characters differ.
0 < s.length ? (() => {
const
c = s[0],
[xs, ys] = span(x => c === x)([
...s.slice(1)
]);

return [
[c, ...xs], ...charGroups(ys)
]
.map(zs => [...zs].join(""));
})() : "";


// ---------------------- TEST -----------------------
// main :: IO()
const main = () =>
charGroups("gHHH5YY++///\\")
.join(", ");


// --------------------- GENERIC ---------------------

// span :: (a -> Bool) -> [a] -> ([a], [a])
const span = p =>
// Longest prefix of xs consisting of elements which
// all satisfy p, tupled with the remainder of xs.
xs => {
const i = xs.findIndex(x => !p(x));

return -1 !== i ? [
xs.slice(0, i),
xs.slice(i)
] : [xs, []];
};

// MAIN ---
return main();
})();</syntaxhighlight>
{{Out}}
{{Out}}
<pre>g, HHH, 5, YY, ++, ///, \</pre>
<pre>g, HHH, 5, YY, ++, ///, \</pre>


=={{header|jq}}==
=={{header|jq}}==
<lang jq># input: a string
<syntaxhighlight lang="jq"># input: a string
# output: a stream of runs
# output: a stream of runs
def runs:
def runs:
Line 1,307: Line 1,675:
end;
end;


"gHHH5YY++///\\" | [runs] | join(", ")</lang>
"gHHH5YY++///\\" | [runs] | join(", ")</syntaxhighlight>
{{out}}
{{out}}
Using the -r ("raw output") command-line option of jq:
Using the -r ("raw output") command-line option of jq:
Line 1,316: Line 1,684:


Starting with
Starting with
<lang javascript>#!/usr/bin/env jsish
<syntaxhighlight lang="javascript">#!/usr/bin/env jsish
;'Split a string based on change of character, in Jsish';
;'Split a string based on change of character, in Jsish';


Line 1,337: Line 1,705:
;splitOnChange('aaa');
;splitOnChange('aaa');
;splitOnChange('aaaba');
;splitOnChange('aaaba');
;splitOnChange('gH HH5YY++//,/\\');</lang>
;splitOnChange('gH HH5YY++//,/\\');</syntaxhighlight>


Then
Then
Line 1,346: Line 1,714:
Giving
Giving


<lang javascript>#!/usr/bin/env jsish
<syntaxhighlight lang="javascript">#!/usr/bin/env jsish
;'Split a string based on change of character, in Jsish';
;'Split a string based on change of character, in Jsish';


Line 1,379: Line 1,747:
splitOnChange('gH HH5YY++//,/\') ==> g, H, , HH, 5, YY, ++, //, ,, /, \
splitOnChange('gH HH5YY++//,/\') ==> g, H, , HH, 5, YY, ++, //, ,, /, \
=!EXPECTEND!=
=!EXPECTEND!=
*/</lang>
*/</syntaxhighlight>


Which tests as:
Which tests as:
Line 1,397: Line 1,765:


=={{header|Julia}}==
=={{header|Julia}}==
<lang julia># v0.6
<syntaxhighlight lang="julia"># v0.6
using IterTools
using IterTools


str = "gHHH5YY++///\\"
str = "gHHH5YY++///\\"
sep = map(join, groupby(identity, str))
sep = map(join, groupby(identity, str))
println("string: $str\nseparated: ", join(sep, ", "))</lang>
println("string: $str\nseparated: ", join(sep, ", "))</syntaxhighlight>


{{out}}
{{out}}
<pre>string: gHHH5YY++///\
<pre>string: gHHH5YY++///\
separated: g, HHH, 5, YY, ++, ///, \</pre>
separated: g, HHH, 5, YY, ++, ///, \</pre>

=={{header|K}}==
<syntaxhighlight lang="k">split: {(&~=':x)_x}

","/ split "gHHH5YY++///\\"</syntaxhighlight>
{{out}}
<pre>"g,HHH,5,YY,++,///,\\"</pre>


=={{header|Kotlin}}==
=={{header|Kotlin}}==
<lang scala>// version 1.0.6
<syntaxhighlight lang="kotlin">// version 1.0.6


fun splitOnChange(s: String): String {
fun splitOnChange(s: String): String {
Line 1,423: Line 1,798:
val s = """gHHH5YY++///\"""
val s = """gHHH5YY++///\"""
println(splitOnChange(s))
println(splitOnChange(s))
}</lang>
}</syntaxhighlight>
{{out}}
<pre>
g, HHH, 5, YY, ++, ///, \
</pre>


=== Using fold() ===
<syntaxhighlight lang="kotlin">

fun splitOnChange(src: String): String =
src.fold("") { acc, c ->
if (acc.isEmpty() || acc.last() == c) "$acc$c" else "$acc, $c"
}

fun main() {
splitOnChange("""gHHH5YY++///\""").also { println(it)}
}
</syntaxhighlight>
{{out}}
{{out}}
<pre>
<pre>
Line 1,431: Line 1,822:


=={{header|Lambdatalk}}==
=={{header|Lambdatalk}}==
<lang scheme>
<syntaxhighlight lang="scheme">
{def mysplit
{def mysplit
{def mysplit.r
{def mysplit.r
Line 1,445: Line 1,836:
{mysplit gHHH5YY++///\}
{mysplit gHHH5YY++///\}
-> g HHH 5 YY ++ /// \
-> g HHH 5 YY ++ /// \
</syntaxhighlight>
</lang>


=={{header|Lua}}==
=={{header|Lua}}==
Note that the backslash must be quoted as a double backslash as Lua uses C-like escape sequences.
Note that the backslash must be quoted as a double backslash as Lua uses C-like escape sequences.
<lang Lua>function charSplit (inStr)
<syntaxhighlight lang="lua">function charSplit (inStr)
local outStr, nextChar = inStr:sub(1, 1)
local outStr, nextChar = inStr:sub(1, 1)
for pos = 2, #inStr do
for pos = 2, #inStr do
Line 1,461: Line 1,852:
end
end


print(charSplit("gHHH5YY++///\\"))</lang>
print(charSplit("gHHH5YY++///\\"))</syntaxhighlight>
{{out}}
{{out}}
<pre>g, HHH, 5, YY, ++, ///, \</pre>
<pre>g, HHH, 5, YY, ++, ///, \</pre>
Line 1,467: Line 1,858:
'''Alternative:'''
'''Alternative:'''
Simply scan difference in reverse order and insert delimiter in place, the loop counter i will not update with length of s.
Simply scan difference in reverse order and insert delimiter in place, the loop counter i will not update with length of s.
<lang lua>function splitdiff(s)
<syntaxhighlight lang="lua">function splitdiff(s)
for i=#s,2,-1 do
for i=#s,2,-1 do
if s:sub(i,i)~=s:sub(i-1,i-1) then
if s:sub(i,i)~=s:sub(i-1,i-1) then
Line 1,474: Line 1,865:
end
end
return s
return s
end</lang>
end</syntaxhighlight>

=={{header|Ksh}}==
<syntaxhighlight lang="ksh">
#!/bin/ksh

# Split a character string based on change of character

# # Variables:
#
str='gHHH5YY++///\'
delim=', '

# # Functions:
#
# # Function _splitonchg(str, delim) - return str split by delim at char change
#
function _splitonchg {
typeset _str ; _str="$1"
typeset _delim ; _delim="$2"
typeset _i _splitstr ; integer _i

for ((_i=1; _i<${#_str}+1; _i++)); do
if [[ "${_str:$((_i-1)):1}" != "${_str:${_i}:1}" ]]; then
_splitstr+="${_str:$((_i-1)):1}${_delim}"
else
_splitstr+="${_str:$((_i-1)):1}"
fi
done
echo "${_splitstr%"${_delim}"*}"
}

######
# main #
######

print "Original: ${str}"
print " Split: $(_splitonchg "${str}" "${delim}")"
</syntaxhighlight>
{{out}}<pre>
Original: gHHH5YY++///\
Split: g, HHH, 5, YY, ++, ///, \</pre>


=={{header|M2000 Interpreter}}==
=={{header|M2000 Interpreter}}==
Stack New open a new stack object as current stack, and keep the old one. After the end of block execution old stack get back as current stack. Data statement push to bottom (we read from top, so using data we get a FIFO type). Letter$ pops a string or raise an error if no string found at the top of stack.
Stack New open a new stack object as current stack, and keep the old one. After the end of block execution old stack get back as current stack. Data statement push to bottom (we read from top, so using data we get a FIFO type). Letter$ pops a string or raise an error if no string found at the top of stack.


<syntaxhighlight lang="m2000 interpreter">
<lang M2000 Interpreter>
Module PrintParts(splitthis$) {
Module PrintParts(splitthis$) {
Def string m$, p$
Def string m$, p$
Line 1,501: Line 1,933:
}
}
PrintParts "gHHH5YY++///\"
PrintParts "gHHH5YY++///\"
</syntaxhighlight>
</lang>


=={{header|Maple}}==
=={{header|Maple}}==
Added an additional backlash to escape the \ character at the end.
Added an additional backlash to escape the \ character at the end.
<lang Maple>splitChange := proc(str::string)
<syntaxhighlight lang="maple">splitChange := proc(str::string)
local start,i,len;
local start,i,len;
start := 1;
start := 1;
Line 1,517: Line 1,949:
printf("%s", str[start..len]);
printf("%s", str[start..len]);
end proc;
end proc;
splitChange("gHHH5YY++///\\");</lang>
splitChange("gHHH5YY++///\\");</syntaxhighlight>
{{out}}
{{out}}
<pre>g, HHH, 5, YY, ++, ///, \</pre>
<pre>g, HHH, 5, YY, ++, ///, \</pre>
Line 1,523: Line 1,955:
=={{header|Mathematica}}/{{header|Wolfram Language}}==
=={{header|Mathematica}}/{{header|Wolfram Language}}==
The backslash (\) must be escaped with another backslash when defining the string.
The backslash (\) must be escaped with another backslash when defining the string.
<lang Mathematica>StringJoin@@Riffle[StringCases["gHHH5YY++///\\", p : (x_) .. -> p], ", "]</lang>
<syntaxhighlight lang="mathematica">StringJoin@@Riffle[StringCases["gHHH5YY++///\\", p : (x_) .. -> p], ", "]</syntaxhighlight>
{{out}}
{{out}}
<pre>g, HHH, 5, YY, ++, ///, \</pre>
<pre>g, HHH, 5, YY, ++, ///, \</pre>


=={{header|MiniScript}}==
=={{header|MiniScript}}==
<lang MiniScript>s = "gHHH5YY++///\"
<syntaxhighlight lang="miniscript">s = "gHHH5YY++///\"
output = []
output = []
lastLetter = s[0]
lastLetter = s[0]
Line 1,536: Line 1,968:
lastLetter = letter
lastLetter = letter
end for
end for
print output.join("")</lang>
print output.join("")</syntaxhighlight>
{{out}}
{{out}}
<pre>g, HHH, 5, YY, ++, ///, \</pre>
<pre>g, HHH, 5, YY, ++, ///, \</pre>


=={{header|Modula-2}}==
=={{header|Modula-2}}==
<lang modula2>MODULE CharacterChange;
<syntaxhighlight lang="modula2">MODULE CharacterChange;
FROM Terminal IMPORT Write,WriteString,WriteLn,ReadChar;
FROM Terminal IMPORT Write,WriteString,WriteLn,ReadChar;


Line 1,565: Line 1,997:


ReadChar
ReadChar
END CharacterChange.</lang>
END CharacterChange.</syntaxhighlight>
{{out}}
{{out}}
<pre>g
<pre>g
Line 1,576: Line 2,008:


=={{header|Nim}}==
=={{header|Nim}}==
<lang nim>proc splitOnDiff(str: string): string =
<syntaxhighlight lang="nim">proc splitOnDiff(str: string): string =
result = ""
result = ""


Line 1,595: Line 2,027:
assert splitOnDiff("""gHHH5YY++///\""") == """g, HHH, 5, YY, ++, ///, \"""
assert splitOnDiff("""gHHH5YY++///\""") == """g, HHH, 5, YY, ++, ///, \"""


echo splitOnDiff("""gHHH5YY++///\""")</lang>
echo splitOnDiff("""gHHH5YY++///\""")</syntaxhighlight>
{{output}}
{{output}}
<pre>g, HHH, 5, YY, ++, ///, \</pre>
<pre>g, HHH, 5, YY, ++, ///, \</pre>


=={{header|ooRexx}}==
=={{header|ooRexx}}==
<lang oorexx>Parse Arg str . /*obtain optional arguments from the CL*/
<syntaxhighlight lang="oorexx">Parse Arg str . /*obtain optional arguments from the CL*/
If str=='' Then str= 'gHHH5YY++///\' /*Not specified? Then use the default.*/
If str=='' Then str= 'gHHH5YY++///\' /*Not specified? Then use the default.*/
i=1
i=1
Line 1,613: Line 2,045:
i=j
i=j
End
End
Say ol</lang>
Say ol</syntaxhighlight>
{{out}}
<pre>g, HHH, 5, YY, ++, ///, \</pre>
=={{header|Pascal}}==
<syntaxhighlight lang="pascal">program SplitChars;
{$IFDEF FPC}
{$MODE DELPHI}{$COPERATORS ON}
{$ENDIF}
const
TestString = 'gHHH5YY++///\';

function SplitAtChars(const S: String):String;
var
i : integer;
lastChar:Char;
begin
result := '';
IF length(s) > 0 then
begin
LastChar := s[1];
result := LastChar;
For i := 2 to length(s) do
begin
if s[i] <> lastChar then
begin
lastChar := s[i];
result += ', ';
end;
result += LastChar;
end;
end;
end;

BEGIN
writeln(SplitAtChars(TestString));
end.</syntaxhighlight>
{{out}}
{{out}}
<pre>g, HHH, 5, YY, ++, ///, \</pre>
<pre>g, HHH, 5, YY, ++, ///, \</pre>


=={{header|Perl}}==
=={{header|Perl}}==
<lang perl>use strict;
<syntaxhighlight lang="perl">use strict;
use warnings;
use warnings;
use feature 'say';
use feature 'say';
Line 1,632: Line 2,099:
}
}
say "Orginal: $string\n Split: 「" . join('」, 「', @S) . "」\n";
say "Orginal: $string\n Split: 「" . join('」, 「', @S) . "」\n";
}</lang>
}</syntaxhighlight>
{{out}}
{{out}}
<pre>Orginal: gHHH5YY++///\
<pre>Orginal: gHHH5YY++///\
Line 1,641: Line 2,108:


=={{header|Phix}}==
=={{header|Phix}}==
<!--<lang Phix>-->
<!--<syntaxhighlight lang="phix">-->
<span style="color: #008080;">function</span> <span style="color: #000000;">split_on_change</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">split_on_change</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">""</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">""</span>
Line 1,659: Line 2,126:
<span style="color: #7060A8;">puts</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">split_on_change</span><span style="color: #0000FF;">(</span><span style="color: #008000;">`gHHH5YY++///\`</span><span style="color: #0000FF;">))</span>
<span style="color: #7060A8;">puts</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">split_on_change</span><span style="color: #0000FF;">(</span><span style="color: #008000;">`gHHH5YY++///\`</span><span style="color: #0000FF;">))</span>
<!--</lang>-->
<!--</syntaxhighlight>-->
{{Out}}
{{Out}}
<pre>
<pre>
g, HHH, 5, YY, ++, ///, \
g, HHH, 5, YY, ++, ///, \
</pre>
</pre>

=={{header|Phixmonti}}==
<syntaxhighlight lang="Phixmonti">/# Rosetta Code problem: https://rosettacode.org/wiki/Split_a_character_string_based_on_change_of_character
by Galileo, 11/2022 #/

include ..\Utilitys.pmt

""
"gHHH5YY++///\" 1 get >ps

len for get
dup tps == if
rot swap chain swap
else
ps> drop >ps
swap ", " tps chain chain swap
endif
endfor

pstack</syntaxhighlight>
{{out}}
<pre>
["g, HHH, 5, YY, ++, ///, \", "gHHH5YY++///\"]

=== Press any key to exit ===</pre>


=={{header|PicoLisp}}==
=={{header|PicoLisp}}==
<lang PicoLisp>(de splitme (Str)
<syntaxhighlight lang="picolisp">(de splitme (Str)
(let (Str (chop Str) Fin)
(let (Str (chop Str) Fin)
(glue
(glue
Line 1,675: Line 2,167:
(conc Fin (cons X))
(conc Fin (cons X))
(link (setq Fin (cons X))) ) ) ) ) ) )
(link (setq Fin (cons X))) ) ) ) ) ) )
(prinl (splitme "gHHH5YY++///\\"))</lang>
(prinl (splitme "gHHH5YY++///\\"))</syntaxhighlight>
{{out}}
{{out}}
<pre>g, HHH, 5, YY, ++, ///, \</pre>
<pre>g, HHH, 5, YY, ++, ///, \</pre>


=={{header|Pike}}==
=={{header|Pike}}==
<syntaxhighlight lang="pike">
<lang Pike>
string input = "gHHH5YY++///\\"; // \ needs escaping
string input = "gHHH5YY++///\\"; // \ needs escaping
string last_char;
string last_char;
Line 1,690: Line 2,182:
}
}


</syntaxhighlight>
</lang>
{{Out}}
{{Out}}
<pre>
<pre>
Line 1,700: Line 2,192:


After executing the following code, for example:
After executing the following code, for example:
<lang plainenglish>Put "abcdef" into a string.
<syntaxhighlight lang="plainenglish">Put "abcdef" into a string.
Slap a rider on the string.</lang>
Slap a rider on the string.</syntaxhighlight>


The rider looks like this:
The rider looks like this:
<lang plainenglish>Original: "abcdef"
<syntaxhighlight lang="plainenglish">Original: "abcdef"
Source: "abcdef"
Source: "abcdef"
Token: ""</lang>
Token: ""</syntaxhighlight>


Now when we <code>Bump the rider.</code>, it looks like this:
Now when we <code>Bump the rider.</code>, it looks like this:
<lang plainenglish>Original: "abcdef"
<syntaxhighlight lang="plainenglish">Original: "abcdef"
Source: "bcdef"
Source: "bcdef"
Token: "a"</lang>
Token: "a"</syntaxhighlight>


Another bump, and:
Another bump, and:
<lang plainenglish>Original: "abcdef"
<syntaxhighlight lang="plainenglish">Original: "abcdef"
Source: "cdef"
Source: "cdef"
Token: "ab"</lang>
Token: "ab"</syntaxhighlight>


Now let's say we have a complete token and want to start a new one. We can
Now let's say we have a complete token and want to start a new one. We can
Line 1,722: Line 2,214:
and now the rider looks like this:
and now the rider looks like this:


<lang plainenglish>Original: "abcdef"
<syntaxhighlight lang="plainenglish">Original: "abcdef"
Source: "cdef"
Source: "cdef"
Token: ""</lang>
Token: ""</syntaxhighlight>


And that's all there is to it.
And that's all there is to it.


<lang plainenglish>To run:
<syntaxhighlight lang="plainenglish">To run:
Start up.
Start up.
Split "gHHH5YY++///\" into some string things by change of character.
Split "gHHH5YY++///\" into some string things by change of character.
Line 1,763: Line 2,255:
If the string thing's next is not nil, write ", " on the console without advancing.
If the string thing's next is not nil, write ", " on the console without advancing.
Put the string thing's next into the string thing.
Put the string thing's next into the string thing.
Repeat.</lang>
Repeat.</syntaxhighlight>
{{out}}
{{out}}
<pre>
<pre>
Line 1,771: Line 2,263:
=={{header|PowerShell}}==
=={{header|PowerShell}}==
{{trans|BBC BASIC}}
{{trans|BBC BASIC}}
<syntaxhighlight lang="powershell">
<lang PowerShell>
function Split-String ([string]$String)
function Split-String ([string]$String)
{
{
Line 1,792: Line 2,284:
$splitString
$splitString
}
}
</syntaxhighlight>
</lang>
<syntaxhighlight lang="powershell">
<lang PowerShell>
Split-String "gHHH5YY++///\"
Split-String "gHHH5YY++///\"
</syntaxhighlight>
</lang>
{{Out}}
{{Out}}
<pre>
<pre>
Line 1,802: Line 2,294:


=={{header|PureBasic}}==
=={{header|PureBasic}}==
<lang purebasic>Procedure splitstring(s$)
<syntaxhighlight lang="purebasic">Procedure splitstring(s$)
Define *p.Character = @s$,
Define *p.Character = @s$,
c_buf.c = *p\c
c_buf.c = *p\c
Line 1,820: Line 2,312:
splitstring("gHHH5YY++///\")
splitstring("gHHH5YY++///\")
Input()
Input()
EndIf</lang>
EndIf</syntaxhighlight>
{{out}}
{{out}}
<pre>g, HHH, 5, YY, ++, ///, \</pre>
<pre>g, HHH, 5, YY, ++, ///, \</pre>
Line 1,828: Line 2,320:
===Python3.6+===
===Python3.6+===
Using [[https://docs.python.org/3.6/library/itertools.html#itertools.groupby itertools.groupby]].
Using [[https://docs.python.org/3.6/library/itertools.html#itertools.groupby itertools.groupby]].
<lang python>from itertools import groupby
<syntaxhighlight lang="python">from itertools import groupby


def splitter(text):
def splitter(text):
Line 1,835: Line 2,327:
if __name__ == '__main__':
if __name__ == '__main__':
txt = 'gHHH5YY++///\\' # Note backslash is the Python escape char.
txt = 'gHHH5YY++///\\' # Note backslash is the Python escape char.
print(f'Input: {txt}\nSplit: {splitter(txt)}')</lang>
print(f'Input: {txt}\nSplit: {splitter(txt)}')</syntaxhighlight>


{{out}}
{{out}}
Line 1,842: Line 2,334:


===Python: Using zip===
===Python: Using zip===
<lang python>def splitterz(text):
<syntaxhighlight lang="python">def splitterz(text):
return (''.join(x + ('' if x == nxt else ', ')
return (''.join(x + ('' if x == nxt else ', ')
for x, nxt in zip(txt, txt[1:] + txt[-1])))
for x, nxt in zip(txt, txt[1:] + txt[-1])))
Line 1,848: Line 2,340:
if __name__ == '__main__':
if __name__ == '__main__':
txt = 'gHHH5YY++///\\'
txt = 'gHHH5YY++///\\'
print(splitterz(txt))</lang>
print(splitterz(txt))</syntaxhighlight>


{{out}}
{{out}}
Line 1,854: Line 2,346:


===Python2===
===Python2===
<lang python>import itertools
<syntaxhighlight lang="python">import itertools


try: input = raw_input
try: input = raw_input
Line 1,864: Line 2,356:
groups.append(''.join(g))
groups.append(''.join(g))
print(' input string: %s' % s)
print(' input string: %s' % s)
print(' output string: %s' % ', '.join(groups))</lang>
print(' output string: %s' % ', '.join(groups))</syntaxhighlight>
{{out}} &nbsp; when using the default input:
{{out}} &nbsp; when using the default input:
<pre>
<pre>
Line 1,872: Line 2,364:


=={{header|Quackery}}==
=={{header|Quackery}}==
<lang Quackery>[ dup size 2 <
<syntaxhighlight lang="quackery">[ dup size 2 <
iff size done
iff size done
behead swap
behead swap
Line 1,887: Line 2,379:
dip [ $ ", " join ]
dip [ $ ", " join ]
recurse join ] is runs$ ( $ --> $ )
recurse join ] is runs$ ( $ --> $ )
</syntaxhighlight>
</lang>
'''Testing in Quackery shell.'''
'''Testing in Quackery shell.'''
<pre>/O> $ "gHHH5YY++///\" runs$ echo$
<pre>/O> $ "gHHH5YY++///\" runs$ echo$
Line 1,897: Line 2,389:
=={{header|Racket}}==
=={{header|Racket}}==
{{trans|Python}}
{{trans|Python}}
<lang racket>#lang racket
<syntaxhighlight lang="racket">#lang racket
(define (split-strings-on-change s)
(define (split-strings-on-change s)
(map list->string (group-by values (string->list s) char=?)))
(map list->string (group-by values (string->list s) char=?)))
Line 1,905: Line 2,397:
<
<
)
)
", "))</lang>
", "))</syntaxhighlight>


{{out}}
{{out}}
Line 1,914: Line 2,406:
{{works with|Rakudo|2017.05}}
{{works with|Rakudo|2017.05}}


<lang perl6>sub group-chars ($str) { $str.comb: / (.) $0* / }
<syntaxhighlight lang="raku" line>sub group-chars ($str) { $str.comb: / (.) $0* / }


# Testing:
# Testing:
Line 1,921: Line 2,413:
put 'Original: ', $string;
put 'Original: ', $string;
put ' Split: ', group-chars($string).join(', ');
put ' Split: ', group-chars($string).join(', ');
}</lang>
}</syntaxhighlight>


{{out}}
{{out}}
Line 1,949: Line 2,441:
=={{header|REXX}}==
=={{header|REXX}}==
===version 1===
===version 1===
<lang rexx>/*REXX program splits a string based on change of character ───► a comma delimited list.*/
<syntaxhighlight lang="rexx">/*REXX program splits a string based on change of character ───► a comma delimited list.*/
parse arg str /*obtain optional arguments from the CL*/
parse arg str /*obtain optional arguments from the CL*/
if str=='' then str= 'gHHH5YY++///\' /*Not specified? Then use the default.*/
if str=='' then str= 'gHHH5YY++///\' /*Not specified? Then use the default.*/
Line 1,959: Line 2,451:
end /*j*/ /* [↓] keep peeling chars until done. */
end /*j*/ /* [↓] keep peeling chars until done. */
say ' input string: ' str /*display the original string & output.*/
say ' input string: ' str /*display the original string & output.*/
say ' output string: ' $ /*stick a fork in it, we're all done. */</lang>
say ' output string: ' $ /*stick a fork in it, we're all done. */</syntaxhighlight>
{{out|output|text=&nbsp; when using the default input:}}
{{out|output|text=&nbsp; when using the default input:}}
<pre>
<pre>
Line 1,967: Line 2,459:


===version 2===
===version 2===
<lang rexx>/* REXX */
<syntaxhighlight lang="rexx">/* REXX */
Parse arg str /*obtain optional arguments from the CL*/
Parse arg str /*obtain optional arguments from the CL*/
if str=='' then str= 'gHHH5YY++///\' /*Not specified? Then use the default.*/
if str=='' then str= 'gHHH5YY++///\' /*Not specified? Then use the default.*/
Line 1,986: Line 2,478:
result=result||x
result=result||x
say ' input string: ' input
say ' input string: ' input
say ' output string: ' result </lang>
say ' output string: ' result </syntaxhighlight>
{{out]]
{{out]]
<pre> input string: gHHH5YY++///\
<pre> input string: gHHH5YY++///\
Line 1,992: Line 2,484:


=={{header|Ring}}==
=={{header|Ring}}==
<lang ring>
<syntaxhighlight lang="ring">
see split("gHHH5YY++///\")
see split("gHHH5YY++///\")


Line 2,007: Line 2,499:
next
next
return split
return split
</syntaxhighlight>
</lang>
Output:
Output:
<pre>
<pre>
g, HHH, 5, YY, ++, ///, \
g, HHH, 5, YY, ++, ///, \
</pre>
</pre>

=={{header|RPL}}==
≪ → text
≪ "" text 1 1 SUB
1 text SIZE '''FOR''' j
text j DUP SUB
'''IF''' DUP2 ≠ '''THEN''' SWAP DROP ", " OVER + '''END'''
ROT SWAP + SWAP
'''NEXT '''DROP
≫ ≫ ‘<span style="color:blue">COMASPLT</span>’ STO


=={{header|Ruby}}==
=={{header|Ruby}}==
<lang ruby>def split(str)
<syntaxhighlight lang="ruby">def split(str)
puts " input string: #{str}"
puts " input string: #{str}"
s = str.chars.chunk(&:itself).map{|_,a| a.join}.join(", ")
s = str.chars.chunk(&:itself).map{|_,a| a.join}.join(", ")
Line 2,021: Line 2,523:
end
end


split("gHHH5YY++///\\")</lang>
split("gHHH5YY++///\\")</syntaxhighlight>


{{out}}
{{out}}
Line 2,030: Line 2,532:


=={{header|Rust}}==
=={{header|Rust}}==
<lang Rust>fn splitter(string: &str) -> String {
<syntaxhighlight lang="rust">fn splitter(string: &str) -> String {
let chars: Vec<_> = string.chars().collect();
let chars: Vec<_> = string.chars().collect();
let mut result = Vec::new();
let mut result = Vec::new();
Line 2,063: Line 2,565:
println!("input string: {}", test_string);
println!("input string: {}", test_string);
println!("output string: {}", splitter(test_string));
println!("output string: {}", splitter(test_string));
}</lang>
}</syntaxhighlight>


{{out}}
{{out}}
Line 2,074: Line 2,576:
output string: g, HHH, 5, YY, ++, ///, \
output string: g, HHH, 5, YY, ++, ///, \
</pre>
</pre>

===Alternate using IterTools===
<syntaxhighlight lang="rust">use itertools::Itertools;

pub fn split_text(s: &str) -> Vec<String> {
let mut r = Vec::new();
for (_, group) in &s.chars().into_iter().group_by(|e| *e) {
r.push(group.map(|e| e.to_string()).join(""));
}
r
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_splitting_text() {
assert_eq!(split_text("gHHH5YY++///\\"), vec!["g", "HHH", "5", "YY", "++", "///", "\\"]);
assert!(split_text("").is_empty());
}
}
</syntaxhighlight>


=={{header|Scala}}==
=={{header|Scala}}==
<lang Scala>// Split a (character) string into comma (plus a blank) delimited strings
<syntaxhighlight lang="scala">// Split a (character) string into comma (plus a blank) delimited strings
// based on a change of character (left to right).
// based on a change of character (left to right).
// See https://rosettacode.org/wiki/Split_a_character_string_based_on_change_of_character#Scala
// See https://rosettacode.org/wiki/Split_a_character_string_based_on_change_of_character#Scala
Line 2,083: Line 2,608:
(s + 'X').sliding(2).map(pair => pair.head + (if (pair.head != pair.last) ", " else "")).mkString("")
(s + 'X').sliding(2).map(pair => pair.head + (if (pair.head != pair.last) ", " else "")).mkString("")


println(runLengthSplit("""gHHH5YY++///\"""))</lang>
println(runLengthSplit("""gHHH5YY++///\"""))</syntaxhighlight>
{{Out}}See it in running in your browser by [https://scalafiddle.io/sf/c4dp8GT/2 ScalaFiddle (JavaScript)]
{{Out}}See it in running in your browser by [https://scalafiddle.io/sf/c4dp8GT/2 ScalaFiddle (JavaScript)]
or by [https://scastie.scala-lang.org/mDoBS77YSG2Z7w5xdAPzcw Scastie (JVM)].
or by [https://scastie.scala-lang.org/mDoBS77YSG2Z7w5xdAPzcw Scastie (JVM)].


<syntaxhighlight lang="scala">
<lang Scala>
def runLengthSplit(s:String):List[String] = {
def runLengthSplit(s:String):List[String] = {
def recursiveSplit(acc:List[String], rest:String): List[String] = rest match {
def recursiveSplit(acc:List[String], rest:String): List[String] = rest match {
Line 2,102: Line 2,627:
val result = runLengthSplit("""gHHH5YY++///\""")
val result = runLengthSplit("""gHHH5YY++///\""")
println(result.mkString(","))
println(result.mkString(","))
</syntaxhighlight>
</lang>
{{Out}}
{{Out}}
<pre>
<pre>
Line 2,109: Line 2,634:


=={{header|Sed}}==
=={{header|Sed}}==
<lang sed>echo 'gHHH5YY++///\' | sed 's/\(.\)\1*/&, /g;s/, $//'</lang>
<syntaxhighlight lang="sed">echo 'gHHH5YY++///\' | sed 's/\(.\)\1*/&, /g;s/, $//'</syntaxhighlight>
Output:
Output:
g, HHH, 5, YY, ++, ///, \
g, HHH, 5, YY, ++, ///, \


=={{header|Sidef}}==
=={{header|Sidef}}==
<lang ruby>func group(str) {
<syntaxhighlight lang="ruby">func group(str) {
gather {
gather {
while (var match = (str =~ /((.)\g{-1}*)/g)) {
while (var match = (str =~ /((.)\g{-1}*)/g)) {
Line 2,122: Line 2,647:
}
}


say group(ARGV[0] \\ 'gHHH5YY++///\\').join(', ')</lang>
say group(ARGV[0] \\ 'gHHH5YY++///\\').join(', ')</syntaxhighlight>
{{out}}
{{out}}
<pre>
<pre>
g, HHH, 5, YY, ++, ///, \
</pre>

=={{header|SNOBOL4}}==
{{works with|SNOBOL4, SPITBOL for Linux}}
<syntaxhighlight lang="snobol4">
* Program: split_on_change_of_character.sbl
* To run: sbl split_on_change_of_character.sbl
* Description: Split a (character) string into comma (plus a blank)
* delimited strings based on a change of character (left to right).
*
* Blanks should be treated as any other character
* (except they are problematic to display clearly).
* The same applies to commas.
*
* For instance, the string:
*
* gHHH5YY++///\
* should be split and show:
*
* g, HHH, 5, YY, ++, ///, \
* Comment: Tested using the Spitbol for Linux version of SNOBOL4

lf = substr(&alphabet,11,1) ;* New line or line feed

* Function split_cc will split a string on a change of character.
define('split_cc(s)tchar,target,post')
:(split_cc_end)
split_cc
tchar = substr(s,1,1) :f(freturn)
split_cc_pat = span(*tchar) . target (rpos(0) | len(1) . tchar rem) . post
split_cc2
s ? split_cc_pat = post :f(split_cc3)
split_cc = (ident(split_cc) target, split_cc ', ' target) :s(split_cc2)
split_cc3
:(return)
split_cc_end

test_string = "gHHH5YY++///\"
output = test_string lf
split_string = split_cc(test_string)
output = split_string

END</syntaxhighlight>
{{out}}
<pre>
gHHH5YY++///\

g, HHH, 5, YY, ++, ///, \
g, HHH, 5, YY, ++, ///, \
</pre>
</pre>


=={{header|Standard ML}}==
=={{header|Standard ML}}==
<lang sml>(*
<syntaxhighlight lang="sml">(*
* Head-Tail implementation of grouping
* Head-Tail implementation of grouping
*)
*)
Line 2,138: Line 2,711:
fun group xs = group' nil xs
fun group xs = group' nil xs


fun groupString str = String.concatWith ", " (map implode (group (explode str)))</lang>
fun groupString str = String.concatWith ", " (map implode (group (explode str)))</syntaxhighlight>


{{out}}
{{out}}
Line 2,146: Line 2,719:
=={{header|Swift}}==
=={{header|Swift}}==


<lang swift>public extension String {
<syntaxhighlight lang="swift">public extension String {
func splitOnChanges() -> [String] {
func splitOnChanges() -> [String] {
guard !isEmpty else {
guard !isEmpty else {
Line 2,172: Line 2,745:
}
}


print("gHHH5YY++///\\".splitOnChanges().joined(separator: ", "))</lang>
print("gHHH5YY++///\\".splitOnChanges().joined(separator: ", "))</syntaxhighlight>


{{out}}
{{out}}
Line 2,179: Line 2,752:


=={{header|Tailspin}}==
=={{header|Tailspin}}==
<lang tailspin>
<syntaxhighlight lang="tailspin">
composer splitEquals
composer splitEquals
<reps> <nextReps>*
<reps> <nextReps>*
Line 2,187: Line 2,760:


'gHHH5YY++///\' -> splitEquals -> !OUT::write
'gHHH5YY++///\' -> splitEquals -> !OUT::write
</syntaxhighlight>
</lang>
{{out}}
{{out}}
<pre>g, HHH, 5, YY, ++, ///, \</pre>
<pre>g, HHH, 5, YY, ++, ///, \</pre>
Line 2,193: Line 2,766:
=={{header|tbas}}==
=={{header|tbas}}==
{{Trans|BBC BASIC}}
{{Trans|BBC BASIC}}
<lang basic>SUB SPLITUNIQUE$(s$)
<syntaxhighlight lang="basic">SUB SPLITUNIQUE$(s$)
DIM c$, d$, split$, i%
DIM c$, d$, split$, i%
c$ = LEFT$(s$, 1)
c$ = LEFT$(s$, 1)
Line 2,209: Line 2,782:


PRINT SPLITUNIQUE$("gHHH5YY++///\")
PRINT SPLITUNIQUE$("gHHH5YY++///\")
END</lang>
END</syntaxhighlight>


=={{header|Tcl}}==
=={{header|Tcl}}==
This is most concise with regular expressions. Note well the two steps: it could be achieved in one very clever regexp, but being that clever is usually a bad idea (for both readability and performance, in this case).
This is most concise with regular expressions. Note well the two steps: it could be achieved in one very clever regexp, but being that clever is usually a bad idea (for both readability and performance, in this case).


<lang Tcl>set string "gHHH5YY++///\\"
<syntaxhighlight lang="tcl">set string "gHHH5YY++///\\"


regsub -all {(.)\1*} $string {\0, } string
regsub -all {(.)\1*} $string {\0, } string
regsub {, $} $string {} string
regsub {, $} $string {} string
puts $string</lang>
puts $string</syntaxhighlight>


{{out}}
{{out}}


<pre>g, HHH, 5, YY, ++, ///, \</pre>
<pre>g, HHH, 5, YY, ++, ///, \</pre>

=={{header|Transd}}==
The task doesn't state explicitly about the order in which substrings should be
displayed. So, here are two variants: one is order-preserving, the other is not
order-preserving.
<syntaxhighlight lang="Scheme">#lang transd

MainModule: {
s: "gHHH5YY++///\\",
_start: (λ
(with res ""
(for c in (split s "") do
(if (neq Char(c) (back res)) (+= res ", "))
(+= res c))
(textout res))

(lout "Second variant: ")

(for v in (values (group-by (split s ""))) do
(textout (if @idx ", ") (join v "")))
)
}</syntaxhighlight>
{{out}}
<pre>
g, HHH, 5, YY, ++, ///, \
Second variant:
++, ///, 5, HHH, YY, \, g
</pre>


=={{header|VBA}}==
=={{header|VBA}}==


<syntaxhighlight lang="vb">
<lang vb>
Option Explicit
Option Explicit


Line 2,260: Line 2,861:
Split_Special = R
Split_Special = R
End Function
End Function
</syntaxhighlight>
</lang>
{{out}}
{{out}}
<pre>g, HHH, 5, YY, ++, ///, \</pre>
<pre>g, HHH, 5, YY, ++, ///, \</pre>

=={{header|V (Vlang)}}==
<syntaxhighlight lang="v (vlang)">fn main() {
println(splitter('gHHH5YY++///\\')) \\ The "\" character needs to be escaped.
}

fn splitter(text string) string {
mut check := text.substr(0, 1)
mut new_text, mut temp := '', ''
for index, _ in text {
temp = text.substr(index, index + 1)
if temp != check {
new_text = new_text + ', '
check = temp
}
new_text = new_text + temp
}
return new_text
}
</syntaxhighlight>

{{out}}
<pre>
g, HHH, 5, YY, ++, ///, \
</pre>


=={{header|Wren}}==
=={{header|Wren}}==
<lang ecmascript>var split = Fn.new { |s|
<syntaxhighlight lang="wren">var split = Fn.new { |s|
if (s.count == 0) return ""
if (s.count == 0) return ""
var res = []
var res = []
Line 2,284: Line 2,910:


var s = "gHHH5YY++///\\"
var s = "gHHH5YY++///\\"
System.print(split.call(s))</lang>
System.print(split.call(s))</syntaxhighlight>


{{out}}
{{out}}
Line 2,292: Line 2,918:


=={{header|XLISP}}==
=={{header|XLISP}}==
<lang lisp>(defun delimit (s)
<syntaxhighlight lang="lisp">(defun delimit (s)
(defun delim (old-list new-list current-char)
(defun delim (old-list new-list current-char)
(if (null old-list)
(if (null old-list)
Line 2,303: Line 2,929:
(list->string (delim (string->list s) '() (car (string->list s)))) )
(list->string (delim (string->list s) '() (car (string->list s)))) )


(display (delimit "gHHH5YY++///\\")) ;; NB. The "\" character needs to be escaped</lang>
(display (delimit "gHHH5YY++///\\")) ;; NB. The "\" character needs to be escaped</syntaxhighlight>
{{out}}
{{out}}
<pre>g, HHH, 5, YY, ++, ///, \</pre>
<pre>g, HHH, 5, YY, ++, ///, \</pre>


=={{header|XPL0}}==
=={{header|XPL0}}==
<lang XPL0>string 0; \change to zero-terminated convention
<syntaxhighlight lang="xpl0">string 0; \change to zero-terminated convention
char S;
char S;
[S:= "gHHH5YY++///\";
[S:= "gHHH5YY++///\";
Line 2,316: Line 2,942:
S:= S+1;
S:= S+1;
];
];
]</lang>
]</syntaxhighlight>


{{out}}
{{out}}
Line 2,322: Line 2,948:
g, HHH, 5, YY, ++, ///, \
g, HHH, 5, YY, ++, ///, \
</pre>
</pre>

=={{header|Yabasic}}==
<syntaxhighlight lang="freebasic">sub esplit$(instring$)
if len(instring$) < 2 return instring$
ret$ = left$(instring$,1)
for i = 2 to len(instring$)
if mid$(instring$,i,1) <> mid$(instring$, i - 1, 1) ret$ = ret$ + ", "
ret$ = ret$ + mid$(instring$, i, 1)
next i
return ret$
end sub

print esplit$("gHHH5YY++///\\")</syntaxhighlight>


=={{header|Z80 Assembly}}==
=={{header|Z80 Assembly}}==
<lang z80>PrintChar equ &BB5A ;Amstrad CPC BIOS call
<syntaxhighlight lang="z80">PrintChar equ &BB5A ;Amstrad CPC BIOS call
Terminator equ 0 ;marks the end of a string
Terminator equ 0 ;marks the end of a string
org &8000
org &8000
Line 2,366: Line 3,005:


StringA:
StringA:
byte "gHHH5YY++///\",0</lang>
byte "gHHH5YY++///\",0</syntaxhighlight>


{{out}}
{{out}}
Line 2,374: Line 3,013:


=={{header|zkl}}==
=={{header|zkl}}==
<lang zkl>fcn group(str){
<syntaxhighlight lang="zkl">fcn group(str){
C,out := str[0],Sink(C);
C,out := str[0],Sink(C);
foreach c in (str[1,*]){ out.write(if(c==C) c else String(", ",C=c)) }
foreach c in (str[1,*]){ out.write(if(c==C) c else String(", ",C=c)) }
out.close();
out.close();
}
}
group("gHHH5YY++///\\").println();</lang>
group("gHHH5YY++///\\").println();</syntaxhighlight>
{{out}}
{{out}}
<pre>
<pre>
Line 2,386: Line 3,025:


=={{header|ZX Spectrum Basic}}==
=={{header|ZX Spectrum Basic}}==
<lang basic> 10 LET s$="gHHH5YY++///\"
<syntaxhighlight lang="basic"> 10 LET s$="gHHH5YY++///\"
20 LET c$=s$(1)
20 LET c$=s$(1)
30 LET n$=c$
30 LET n$=c$
Line 2,394: Line 3,033:
70 LET c$=s$(i)
70 LET c$=s$(i)
80 NEXT i
80 NEXT i
90 PRINT n$</lang>
90 PRINT n$</syntaxhighlight>
{{out}}
{{out}}
<pre>g, HHH, 5, YY, ++, ///, \</pre>
<pre>g, HHH, 5, YY, ++, ///, \</pre>

Latest revision as of 15:51, 9 February 2024

Task
Split a character string based on change of character
You are encouraged to solve this task according to the task description, using any language you may know.


Task

Split a (character) string into comma (plus a blank) delimited strings based on a change of character   (left to right).

Show the output here   (use the 1st example below).


Blanks should be treated as any other character   (except they are problematic to display clearly).   The same applies to commas.


For instance, the string:

 gHHH5YY++///\ 

should be split and show:

 g, HHH, 5, YY, ++, ///, \ 


Other tasks related to string operations:
Metrics
Counting
Remove/replace
Anagrams/Derangements/shuffling
Find/Search/Determine
Formatting
Song lyrics/poems/Mad Libs/phrases
Tokenize
Sequences



11l

Translation of: C++
F split(input, delim)
   V res = ‘’
   L(ch) input
      I !res.empty & ch != res.last
         res ‘’= delim
      res ‘’= ch
   R res

print(split(‘gHHH5YY++///\’, ‘, ’))
Output:
g, HHH, 5, YY, ++, ///, \

8080 Assembly

	org	100h
	jmp	demo
	;;;	Split the string under DE on changing characters,
	;;;	and store the result at HL.
split:	ldax	d	; Load character from string
spcopy:	mov	m,a	; Store in output
	cpi	'$'	; CP/M string terminator
	rz		; Stop when the end is reached
	mov	b,a	; Store previous character in B
	inx	d	; Increment input pointer
	inx	h	; Increment output pointer
	ldax	d	; Get next character
	cmp	b	; Same as previous character?
	jz	spcopy	; Then just copy it
	cpi	'$'	; Otherwise, if it is the en 
	jz	spcopy	; Then just copy it as well
	mvi	m,','	; Otherwise, add a comma and a space
	inx	h
	mvi	m,' '
	inx	h
	jmp	spcopy
	;;;	Demo code
demo:	lxi	d,string
	lxi	h,out
	call	split	; Split the string
	lxi	d,out
	mvi	c,9	; And print it using CP/M
	jmp	5
string:	db	'gHHH5YY++///',5Ch,'$'
out:	equ	$
Output:
g, HHH, 5, YY, ++, ///, \

8086 Assembly

	cpu	8086
	org	100h
section	.text
	jmp	demo
	;;;	Split the string at DS:SI on changing characters,
	;;;	and store the result at ES:DI.
split:	lodsb		; Load character	
.copy:	stosb		; Store in output
	cmp	al,'$'	; Done yet?
	je	.out	; If so, stop.
	mov	ah,al	; Store previous character
	lodsb		; Get next character
	cmp	al,ah	; Same character?
	je	.copy	; Then just copy it
	cmp	al,'$'	; End of string?
	je	.copy	; Then just copy it too
	mov	dl,al
	mov	ax,', '	; Otherwise, add a comma and a space
	stosw
	mov	al,dl
	jmp	.copy
.out:	ret
	;;;	Demo code
demo:	mov	si,string
	mov	di,buf
	call	split	; Split the string
	mov	dx,buf
	mov	ah,9
	int	21h	; And print the result using DOS
	ret
section	.data
string:	db	'gHHH5YY++///\$'
section	.bss
buf:	resb	32
Output:
g, HHH, 5, YY, ++, ///, \

AArch64 Assembly

Works with: as version Raspberry Pi 3B version Buster 64 bits
/* ARM assembly AARCH64 Raspberry PI 3B */
/*  program splitcar64.s   */

/*******************************************/
/* Constantes file                         */
/*******************************************/
/* for this file see task include a file in language AArch64 assembly*/
.include "../includeConstantesARM64.inc"
 
/*********************************/
/* Initialized data              */
/*********************************/
.data
szCarriageReturn:   .asciz "\n"
szString1:          .asciz "gHHH5YY++///\\"
/*   IMPORTANT REMARK for compiler as 
The way to get special characters into a string is to escape these characters: precede them
with a backslash ‘\’ character. For example ‘\\’ represents one backslash: the first \ is
an escape which tells as to interpret the second character literally as a backslash (which
prevents as from recognizing the second \ as an escape character).
*/
 
/*********************************/
/* UnInitialized data            */
/*********************************/
.bss  
sBuffer:               .skip  100
 
/*********************************/
/*  code section                 */
/*********************************/
.text
.global main 
main:                              // entry of program 
 
    ldr x0,qAdrszString1           // input string address
    ldr x1,qAdrsBuffer             // output buffer address
    bl split 
 
    ldr x0,qAdrsBuffer
    bl affichageMess               // display message
    ldr x0,qAdrszCarriageReturn
    bl affichageMess 
 
 
100:                               // standard end of the program 
    mov x0,0                       // return code
    mov x8,EXIT                    // request to exit program
    svc 0                          // perform the system call
 
qAdrszString1:            .quad szString1
qAdrszCarriageReturn:     .quad szCarriageReturn
qAdrsBuffer:              .quad sBuffer
 
/******************************************************************/
/*     generate value                                  */ 
/******************************************************************/
/* x0 contains the address of input string  */
/* x1 contains the address of output buffer  */
 
split:
    stp x1,lr,[sp,-16]!            // save  registers
    mov x4,0                       // indice loop input string
    mov x5,0                       // indice buffer
    ldrb w2,[x0,x4]                // read first char in reg x2
    cbz x2,4f                       // if null -> end
    strb w2,[x1,x5]                // store char in buffer
    add x5,x5,1                    // increment location buffer
1:
    ldrb w3,[x0,x4]                //read char[x4] in reg x3
    cbz x3,4f                      // if null  end
    cmp x2,x3                      // compare two characters
    bne 2f
    strb w3,[x1,x5]                // = -> store char in buffer   
    b 3f                           // loop
2:
    mov x2,','                    // else store comma in buffer
    strb w2,[x1,x5]                // store char in buffer
    add x5,x5,1
    mov x2,' '                    // and store space in buffer
    strb w2,[x1,x5]
    add x5,x5,1
    strb w3,[x1,x5]               // and store input char in buffer
    mov x2,x3                     // and maj x2 with new char
3:
    add x5,x5,1                   // increment indices
    add x4,x4,1
    b 1b                          // and loop
4:
    strb w3,[x1,x5]               // store zero final in buffer
100:
    ldp x1,lr,[sp],16             // restaur  2 registers
    ret                           // return to address lr x30
/********************************************************/
/*        File Include fonctions                        */
/********************************************************/
/* for this file see task include a file in language AArch64 assembly */
.include "../includeARM64.inc"
Output:
 gg, HHH, 5, YY, ++, ///, \ 

Action!

PROC Split(CHAR ARRAY s)
  BYTE i
  CHAR curr,last

  i=1 last=s(1)
  Put('")
  WHILE i<=s(0)
  DO
    curr=s(i)
    IF curr#last THEN
      Print(", ")
    FI
    Put(curr)
    last=curr
    i==+1
  OD
  Put('")
RETURN

PROC Test(CHAR ARRAY s)
  PrintF("Input: ""%S""%E",s)
  Print("Split: ") Split(s)
  PutE() PutE()
RETURN

PROC Main()
  Test("gHHH5YY++///\")
  Test("gHHH   5++,,,///\")
RETURN
Output:

Screenshot from Atari 8-bit computer

Input: "gHHH5YY++///\"
Split: "g, HHH, 5, YY, ++, ///, \"

Input: "gHHH   5++,,,///\"
Split: "g, HHH,    , 5, ++, ,,,, ///, \"

Ada

with Ada.Text_IO;
procedure Split is 
  procedure Print_Tokens (s : String) is
    i, j : Integer := s'First;
  begin
    loop
      while j<=s'Last and then s(j)=s(i) loop j := j + 1; end loop;
      if i/=s'first then Ada.Text_IO.Put (", "); end if;
      Ada.Text_IO.Put (s(i..j-1));
      i := j;
      exit when j>s'last;
    end loop;
  end Print_Tokens;
begin
  Print_Tokens ("gHHH5YY+++");
end split;

ALGOL 68

BEGIN
    # returns s with ", " added between each change of character #
    PROC split on characters = ( STRING s )STRING:
         IF s = "" THEN
            # empty string #
            ""
         ELSE
            # allow for 3 times as many characters as in the string #
            # this would handle a string of unique characters       #
            [ 3 * ( ( UPB s - LWB s ) + 1 ) ]CHAR result;
            INT  r pos  := LWB result;
            CHAR s char := s[ LWB s ];
            FOR s pos FROM LWB s TO UPB s DO
                IF s char /= s[ s pos ] THEN
                    # change of character - insert ", " #
                    result[ r pos     ] := ",";
                    result[ r pos + 1 ] := " ";
                    r pos +:= 2;
                    s char := s[ s pos ]
                FI;
                result[ r pos ] := s[ s pos ];
                r pos +:= 1
            OD;
            # return the used portion of the result #
            result[ 1 : r pos - 1 ]
         FI ; # split on characters #

    print( ( split on characters( "gHHH5YY++///\" ), newline ) )
END
Output:
g, HHH, 5, YY, ++, ///, \

Amazing Hopper

VERSION 1: string

#include <basico.h>

#define INICIO  1
#define CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789\"+-/ \\:,;:_*"

algoritmo
    
    objetivo = "gHHH5YY\"\"++    ///,,,\\", indice=0
    largo=0, sublargo=0, v=0

    #( largo = len(indice:=(onechar(CHARS,objetivo))) )

    t=0, nuevo=""
    para cada caracter ( v, indice, largo )
         #(t = replicate(v, sublargo := ((poschar(INICIO, v, objetivo) - 1 ) ) ))
         #(nuevo = cat( cat(nuevo, t), ", "))         
         objetivo+=sublargo
    siguiente
    nuevo -= 2
    imprimir( "NEW STRING=\n", nuevo,NL)

terminar
Output:
$ hopper3 basica/splitrep.bas 
NEW STRING=
g, HHH, 5, YY, "", ++,     , ///, ,,,, \


VERSION 2: arrays

#include <basico.h>

#define INICIO  1
#define CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789\"+-/ \\:,;:_*"

algoritmo
    
    objetivo = "gHHH5YY\"\"++    ///,,,,\\", indice=0
    largo=0, sublargo=0, lista={}, v=0
    
    #( largo = len(indice:=(onechar(CHARS,objetivo))) )

    para cada caracter ( v, indice, largo )
         #( replicate(v, sublargo := ((poschar(INICIO, v, objetivo) - 1 ))))
         meter en( lista )
         objetivo+=sublargo
    siguiente
    
    imprimir( "LISTA=\n", lista, NL )


terminar
Output:
$ hopper3 basica/splitrep2.bas 
LISTA=
g,HHH,5,YY,"",++,    ,///,,,,,,\

ANSI BASIC

Works with: Decimal BASIC
REM >split
DECLARE EXTERNAL FUNCTION FN_split$

PRINT FN_split$( "gHHH5YY++///\" )
END

EXTERNAL FUNCTION FN_split$( s$ )
LET c$ = s$(1:1)
LET split$ = ""
FOR i = 1 TO LEN(s$)
  LET d$ = s$(i:i)
  IF d$ <> c$ THEN
    LET split$ = split$ & ", "
    LET c$ = d$
  END IF
  LET split$ = split$ & d$
NEXT i
LET FN_split$ = split$
END FUNCTION
Output:
g, HHH, 5, YY, ++, ///, \

APL

Works with: Dyalog APL
split  2(', '),¨(⊢≠¯1⌽⊢)⊂⊢
Output:
      split 'gHHH5YY++///\'
g, HHH, 5, YY, ++, ///, \

AppleScript

Functional

Translation of: JavaScript
intercalate(", ", ¬
    map(curry(intercalate)'s |λ|(""), ¬
        group("gHHH5YY++///\\")))

--> "g, HHH, 5, YY, ++, ///, \\"


-- GENERIC FUNCTIONS ----------------------------------------------------------
-- curry :: (Script|Handler) -> Script
on curry(f)
    script
        on |λ|(a)
            script
                on |λ|(b)
                    |λ|(a, b) of mReturn(f)
                end |λ|
            end script
        end |λ|
    end script
end curry

-- foldl :: (a -> b -> a) -> a -> [b] -> a
on foldl(f, startValue, xs)
    tell mReturn(f)
        set v to startValue
        set lng to length of xs
        repeat with i from 1 to lng
            set v to |λ|(v, item i of xs, i, xs)
        end repeat
        return v
    end tell
end foldl

-- group :: Eq a => [a] -> [[a]]
on group(xs)
    script eq
        on |λ|(a, b)
            a = b
        end |λ|
    end script
    
    groupBy(eq, xs)
end group

-- groupBy :: (a -> a -> Bool) -> [a] -> [[a]]
on groupBy(f, xs)
    set mf to mReturn(f)
    
    script enGroup
        on |λ|(a, x)
            if length of (active of a) > 0 then
                set h to item 1 of active of a
            else
                set h to missing value
            end if
            
            if h is not missing value and mf's |λ|(h, x) then
                {active:(active of a) & x, sofar:sofar of a}
            else
                {active:{x}, sofar:(sofar of a) & {active of a}}
            end if
        end |λ|
    end script
    
    if length of xs > 0 then
        tell foldl(enGroup, {active:{item 1 of xs}, sofar:{}}, tail(xs))
            if length of (its active) > 0 then
                its sofar & its active
            else
                {}
            end if
        end tell
    else
        {}
    end if
end groupBy

-- intercalate :: Text -> [Text] -> Text
on intercalate(strText, lstText)
    set {dlm, my text item delimiters} to {my text item delimiters, strText}
    set strJoined to lstText as text
    set my text item delimiters to dlm
    return strJoined
end intercalate

-- map :: (a -> b) -> [a] -> [b]
on map(f, xs)
    tell mReturn(f)
        set lng to length of xs
        set lst to {}
        repeat with i from 1 to lng
            set end of lst to |λ|(item i of xs, i, xs)
        end repeat
        return lst
    end tell
end map

-- Lift 2nd class handler function into 1st class script wrapper 
-- mReturn :: Handler -> Script
on mReturn(f)
    if class of f is script then
        f
    else
        script
            property |λ| : f
        end script
    end if
end mReturn

-- tail :: [a] -> [a]
on tail(xs)
    if length of xs > 1 then
        items 2 thru -1 of xs
    else
        {}
    end if
end tail
Output:
g, HHH, 5, YY, ++, ///, \

Straightforward

(Also case-sensitve.)

on splitAtCharacterChanges(input)
    set len to (count input)
    if (len < 2) then return input
    set chrs to input's characters
    set currentChr to beginning of chrs
    considering case
        repeat with i from 2 to len
            set thisChr to item i of chrs
            if (thisChr is not currentChr) then
                set item i of chrs to ", " & thisChr
                set currentChr to thisChr
            end if
        end repeat
    end considering
    set astid to AppleScript's text item delimiters
    set AppleScript's text item delimiters to ""
    set output to chrs as text
    set AppleScript's text item delimiters to astid
    
    return output
end splitAtCharacterChanges

-- Test code:
splitAtCharacterChanges("gHHH5YY++///\\")
Output:
"g, HHH, 5, YY, ++, ///, \\"

ASObjC

use AppleScript version "2.4" -- OS X 10.10 (Yosemite) or later
use framework "Foundation"

on splitAtCharacterChanges(input)
    tell (current application's class "NSMutableString"'s stringWithString:(input)) to ¬
        return (its stringByReplacingOccurrencesOfString:("(.)\\1*+(?!$)") withString:("$0, ") ¬
            options:(current application's NSRegularExpressionSearch) range:({0, its |length|()})) as text
end splitAtCharacterChanges

-- Test code:
splitAtCharacterChanges("gHHH5YY++///\\")
Output:
"g, HHH, 5, YY, ++, ///, \\"

ARM Assembly

Works with: as version Raspberry Pi
/* ARM assembly Raspberry PI  */
/*  program splitcar.s   */
 
/************************************/
/* Constantes                       */
/************************************/
.equ STDOUT, 1     @ Linux output console
.equ EXIT,   1     @ Linux syscall
.equ WRITE,  4     @ Linux syscall

/*********************************/
/* Initialized data              */
/*********************************/
.data
szCarriageReturn:   .asciz "\n"
szString1:          .asciz "gHHH5YY++///\\"
/*   IMPORTANT REMARK for compiler as 
The way to get special characters into a string is to escape these characters: precede them
with a backslash ‘\’ character. For example ‘\\’ represents one backslash: the first \ is
an escape which tells as to interpret the second character literally as a backslash (which
prevents as from recognizing the second \ as an escape character).
*/

/*********************************/
/* UnInitialized data            */
/*********************************/
.bss  
sBuffer:               .skip  100

/*********************************/
/*  code section                 */
/*********************************/
.text
.global main 
main:                                             @ entry of program 

    ldr r0,iAdrszString1                          @ input string address
    ldr r1,iAdrsBuffer                            @ output buffer address
    bl split 

    ldr r0,iAdrsBuffer
    bl affichageMess                              @ display message
    ldr r0,iAdrszCarriageReturn
    bl affichageMess 


100:                                              @ standard end of the program 
    mov r0, #0                                    @ return code
    mov r7, #EXIT                                 @ request to exit program
    svc #0                                        @ perform the system call
 
iAdrszString1:            .int szString1
iAdrszCarriageReturn:     .int szCarriageReturn
iAdrsBuffer:              .int sBuffer

/******************************************************************/
/*     generate value                                  */ 
/******************************************************************/
/* r0 contains the address of input string  */
/* r1 contains the address of output buffer  */

split:
    push {r1-r5,lr}                           @ save registers
    mov r4,#0                                 @ indice loop input string
    mov r5,#0                                 @ indice buffer
    ldrb r2,[r0,r4]                           @ read first char in reg r2
    cmp r2,#0                                 @ if null -> end
    beq 3f
    strb r2,[r1,r5]                           @ store char in buffer
    add r5,#1                                 @ increment location buffer
1:
    ldrb r3,[r0,r4]                           @read char[r4] in reg r3
    cmp r3,#0                                 @ if null  end
    beq 3f
    cmp r2,r3                                 @ compare two characters
    streqb r3,[r1,r5]                         @ = -> store char in buffer   
    beq 2f                                    @ loop

    mov r2,#','                               @ else store comma in buffer
    strb r2,[r1,r5]                           @ store char in buffer
    add r5,#1
    mov r2,#' '                               @ and store space in buffer
    strb r2,[r1,r5]
    add r5,#1
    strb r3,[r1,r5]                           @ and store input char in buffer
    mov r2,r3                                 @ and maj r2 with new char
2:
    add r5,#1                                 @ increment indices
    add r4,#1
    b 1b                                      @ and loop
3:
    strb r3,[r1,r5]                           @ store zero final in buffer
100:
    pop {r1-r5,lr}
    bx lr                                     @ return 

/******************************************************************/
/*     display text with size calculation                         */ 
/******************************************************************/
/* r0 contains the address of the message */
affichageMess:
    push {r0,r1,r2,r7,lr}                          @ save  registres
    mov r2,#0                                      @ counter length 
1:                                                 @ loop length calculation 
    ldrb r1,[r0,r2]                                @ read octet start position + index 
    cmp r1,#0                                      @ if 0 its over 
    addne r2,r2,#1                                 @ else add 1 in the length 
    bne 1b                                         @ and loop 
                                                   @ so here r2 contains the length of the message 
    mov r1,r0                                      @ address message in r1 
    mov r0,#STDOUT                                 @ code to write to the standard output Linux 
    mov r7, #WRITE                                 @ code call system "write" 
    svc #0                                         @ call systeme 
    pop {r0,r1,r2,r7,lr}                           @ restaur des  2 registres */ 
    bx lr                                          @ return  

output : gg, HHH, 5, YY, ++, ///, \

Arturo

parts: [] current: ""
loop split {gHHH5YY++///\} 'ch [
    if? or? empty? current
            contains? current ch -> 'current ++ ch
    else [
        'parts ++ current
        current: new ch
    ]
]
'parts ++ current
print parts
Output:
g HHH 5 YY ++ /// \

AutoHotkey

Split_Change(str){
	for i, v in StrSplit(str)
		res .= (v=prev) ? v : (res?", " :"") v	, prev := v
	return res
}

Examples:

str := "gHHH5YY++///\"
MsgBox % Split_Change(str)

Outputs:

g, HHH, 5, YY, ++, ///, \

RegEx Version

Split_Change(str){
	return RegExReplace(str, "(.)\1*(?!$)", "$0, ")
}

Examples:

str := "gHHH5YY++///\"
MsgBox % Split_Change(str)

Outputs:

g, HHH, 5, YY, ++, ///, \

AWK

# syntax: GAWK -f SPLIT_A_CHARACTER_STRING_BASED_ON_CHANGE_OF_CHARACTER.AWK
BEGIN {
    str = "gHHH5YY++///\\"
    printf("old: %s\n",str)
    printf("new: %s\n",split_on_change(str))
    exit(0)
}
function split_on_change(str,  c,i,new_str) {
    new_str = substr(str,1,1)
    for (i=2; i<=length(str); i++) {
      c = substr(str,i,1)
      if (substr(str,i-1,1) != c) {
        new_str = new_str ", "
      }
      new_str = new_str c
    }
    return(new_str)
}
Output:
old: gHHH5YY++///\
new: g, HHH, 5, YY, ++, ///, \

BaCon

Literal strings in BaCon are passed to the C compiler as they are; a backslash therefore needs to be escaped.

txt$ = "gHHH5YY++///\\"

c$ = LEFT$(txt$, 1)

FOR x = 1 TO LEN(txt$)
    d$ = MID$(txt$, x, 1)
    IF d$ <> c$ THEN
        PRINT ", ";
        c$ = d$
    END IF
    PRINT d$;
NEXT
Output:
g, HHH, 5, YY, ++, ///, \

BASIC256

function split$(instring$)
    if length(instring$) < 2 then return instring$
    ret$ = left(instring$,1)
        for i = 2 to length(instring$)
	    if mid(instring$,i,1) <> mid(instring$, i-1, 1) then ret$ += ", "
	    ret$ += mid(instring$, i, 1)
	next i
    return ret$
end function

print split$("gHHH5YY++///\")

BBC BASIC

REM >split
PRINT FN_split( "gHHH5YY++///\" )
END

DEF FN_split( s$ )
LOCAL c$, split$, d$, i%
c$ = LEFT$( s$, 1 )
split$ = ""
FOR i% = 1 TO LEN s$
  LET d$ = MID$( s$, i%, 1 )
  IF d$ <> c$ THEN
    split$ += ", "
    c$ = d$
  ENDIF
  split$ += d$
NEXT
= split$
Output:
g, HHH, 5, YY, ++, ///, \

BQN

Split  (+`»)
Join  {𝕨´𝕩}

", " JoinSplit "gHHH5YY++///\"
Output:
"g, HHH, 5, YY, ++, ///, \"

C

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *split(char *str);
int main(int argc,char **argv)
{
	char input[13]="gHHH5YY++///\\";
	printf("%s\n",split(input));
}
char *split(char *str)
{
	char last=*str,*result=malloc(3*strlen(str)),*counter=result;
	for (char *c=str;*c;c++) {
		if (*c!=last) {
			strcpy(counter,", ");
			counter+=2;
			last=*c;
		}
		*counter=*c;
		counter++;
	}
	*(counter--)='\0';
	return realloc(result,strlen(result));
}
Output:
g, HHH, 5, YY, ++, ///, \

C#

using System;
using System.Linq;
using System.Collections.Generic;

public class Program
{
    string s = @"gHHH5YY++///\";
    Console.WriteLine(s.RunLengthSplit().Delimit(", "));
}

public static class Extensions
{
    public static IEnumerable<string> RunLengthSplit(this string source) {
        using (var enumerator = source.GetEnumerator()) {
            if (!enumerator.MoveNext()) yield break;
            char previous = enumerator.Current;
            int count = 1;
            while (enumerator.MoveNext()) {
                if (previous == enumerator.Current) {
                    count++;
                } else {
                    yield return new string(Enumerable.Repeat(previous, count).ToArray());
                    previous = enumerator.Current;
                    count = 1;
                }
            }
            yield return new string(Enumerable.Repeat(previous, count).ToArray());
        }
    }

    public static string Delimit<T>(this IEnumerable<T> source, string separator = "") => string.Join(separator ?? "", source);
}
Output:
g, HHH, 5, YY, ++, ///, \

C++

// Solution for http://rosettacode.org/wiki/Split_a_character_string_based_on_change_of_character
#include<string>
#include<iostream>

auto split(const std::string& input, const std::string& delim){
	std::string res;
	for(auto ch : input){
		if(!res.empty() && ch != res.back())
			res += delim;
		res += ch;
	}
	return res;
}

int main(){
	std::cout << split("gHHH5  ))YY++,,,///\\", ", ") << std::endl;
}
Output:
g, HHH, 5,   , )), YY, ++, ,,,, ///, \

Clojure

(defn print-cchanges [s]
  (println (clojure.string/join ", " (map first (re-seq #"(.)\1*" s)))))

(print-cchanges "gHHH5YY++///\\")
Output:
g, HHH, 5, YY, ++, ///, \

CLU

% Split a string based on a change of character
split_on_change = iter (s: string) yields (string)
    part: string := ""
    for c: char in string$chars(s) do
        if ~string$empty(part) 
        cand part[string$size(part)] ~= c then 
            yield(part)
            part := ""
        end
        part := part || string$c2s(c)
    end
    yield(part)
end split_on_change 

start_up = proc ()
    po: stream := stream$primary_output()
    str: string := "gHHH5YYY++///\\" % \\ escapes, as in C
    rslt: string := ""
    first: bool := true
    
    for part: string in split_on_change(str) do
        if first then first := false
        else rslt := rslt || ", "
        end
        rslt := rslt || part
    end
    stream$putl(po, rslt)
end start_up
Output:
g, HHH, 5, YYY, ++, ///, \

COBOL

       identification division.
       program-id. split-ch.
       data division.
       1 split-str pic x(30) value space.
       88 str-1 value "gHHH5YY++///\".
       88 str-2 value "gHHH5  ))YY++,,,///\".
       1 binary.
        2 ptr pic 9(4) value 1.
        2 str-start pic 9(4) value 1.
        2 delim-len pic 9(4) value 1.
        2 split-str-len pic 9(4) value 0.
        2 trash-9 pic 9(4) value 0.
       1 delim-char pic x value space.
       1 delim-str pic x(6) value space.
       1 trash-x pic x.
       procedure division.
           display "Requested string"
           set str-1 to true
           perform split-init-and-go
           display space
           display "With spaces and commas"
           set str-2 to true
           perform split-init-and-go
           stop run
           .

       split-init-and-go.
           move 1 to ptr
           move 0 to split-str-len
           perform split
           .

       split.
           perform get-split-str-len
           display split-str (1:split-str-len)
           perform until ptr > split-str-len
               move ptr to str-start
               move split-str (ptr:1) to delim-char
               unstring split-str (1:split-str-len)
                   delimited all delim-char
                   into trash-x delimiter delim-str
                   pointer ptr
               end-unstring
               subtract str-start from ptr giving delim-len
               move split-str (str-start:delim-len)
                   to delim-str (1:delim-len)
               display delim-str (1:delim-len) with no advancing
               if ptr <= split-str-len
                   display ", " with no advancing
               end-if
           end-perform
           display space
           .

       get-split-str-len.
           inspect function reverse (split-str) tallying
               trash-9 for leading space
               split-str-len for characters after space
           .

       end program split-ch.
Output:
Requested string
gHHH5YY++///\
g, HHH, 5, YY, ++, ///, \

With spaces and commas
gHHH5  ))YY++,,,///\
g, HHH, 5,   , )), YY, ++, ,,,, ///, \

Common Lisp

(defun split (string)
  (loop :for prev := nil :then c
     :for c :across string
     :do (format t "~:[~;, ~]~c" (and prev (char/= c prev)) c)))

(split "gHHH5YY++///\\")
Output:
g, HHH, 5, YY, ++, ///, \

Doing more work that what's being ask, the following solution builds a list of strings then output it:

(defun split (string)
  (flet ((make-buffer ()
           (make-array 0 :element-type 'character :adjustable t :fill-pointer t)))
    (loop with buffer = (make-buffer)
          with result
          for prev = nil then c
          for c across string
          when (and prev (char/= c prev))
            do (push buffer result)
               (setf buffer (make-buffer))
          do (vector-push-extend c buffer)
          finally (push buffer result)
                  (format t "~{~A~^, ~}"(nreverse result)))))

(split "gHHH5YY++///\\")
Output:
g, HHH, 5, YY, ++, ///, \

Cowgol

include "cowgol.coh";

sub split(in: [uint8], buf: [uint8]): (out: [uint8]) is
    out := buf;
    loop
        [buf] := [in];
        if [in] == 0 then break; end if;
        if [in] != [@next in] and [@next in] != 0 then
            [buf+1] := ',';
            [buf+2] := ' ';
            buf := buf+2;
        end if;
        buf := buf+1;
        in := in+1;
    end loop;
end sub;

var buf: uint8[32];

print(split("gHHH5YY++//\\", &buf[0]));
print_nl();
Output:
g, HHH, 5, YY, ++, //, \

D

import std.stdio;

void main() {
    auto source = "gHHH5YY++///\\";

    char prev = source[0];
    foreach(ch; source) {
        if (prev != ch) {
            prev = ch;
            write(", ");
        }
        write(ch);
    }
    writeln();
}
Output:
g, HHH, 5, YY, ++, ///, \

Delphi

Works with: Delphi version 6.0


function SplitStringCharChange(S: string): string;
{Split string whenever the previous char is different from the current one}
var I: integer;
var C: char;
begin
Result:='';
{Copy string to output}
for I:=1 to Length(S) do
	begin
	Result:=Result+S[I];
	{Appended ", " if the next char is different}
	if (I<Length(S)) and (S[I]<>S[I+1]) then Result:=Result+', ';
	end;
end;


procedure ShowSplitString(Memo: TMemo);
const S1 = 'gHHH5YY++///\';
var S2: string;
begin
Memo.Lines.Add(S1);
S2:=SplitStringCharChange(S1);
Memo.Lines.Add(S2);
end;
Output:
gHHH5YY++///\
g, HHH, 5, YY, ++, ///, \
Elapsed Time: 1.767 ms.


Dyalect

func String.SmartSplit() {
    var c
    var str = ""
    var last = this.Length() - 1
 
    for n in 0..last {
        if c && this[n] != c {
            str += ", "
        }
        c = this[n]
        str += c
    }
 
    str
}
 
print("gHHH5YY++///\\".SmartSplit())
Output:
g, HHH, 5, YY, ++, ///, \

EasyLang

a$ = "gHHH5YY++///\\"
a$[] = strchars a$
cp$ = a$[1]
for c$ in a$[]
   if c$ <> cp$
      s$ &= ", "
      cp$ = c$
   .
   s$ &= c$
.
print s$
Output:
g, HHH, 5, YY, ++, ///, \

Elixir

split = fn str ->
          IO.puts " input string: #{str}"
          String.graphemes(str)
          |> Enum.chunk_by(&(&1))
          |> Enum.map_join(", ", &Enum.join &1)
          |> fn s -> IO.puts "output string: #{s}" end.()
        end

split.("gHHH5YY++///\\")
Output:
 input string: gHHH5YY++///\
output string: g, HHH, 5, YY, ++, ///, \

F#

open System.Text.RegularExpressions
let splitRuns s = Regex("""(.)\1*""").Matches(s) |> Seq.cast<Match> |> Seq.map (fun m -> m.Value) |> Seq.toList
printfn "%A" (splitRuns """gHHH5YY++///\""")
Output:
["g"; "HHH"; "5"; "YY"; "++"; "///"; "\"]

Factor

USE: splitting.monotonic
"gHHH5YY++///\\"
"aaabbccccdeeff" [ [ = ] monotonic-split ", " join print ] bi@
Output:
g, HHH, 5, YY, ++, ///, \
aaa, bb, cccc, d, ee, ff

Forth

Works with: Gforth version 0.7.3
CREATE A 0 ,               
: C@A+   A @ C@  [ 1 CHARS ]L A +! ;
: SPLIT. ( c-addr u --) SWAP A !  A @ C@
   BEGIN OVER WHILE
     C@A+  TUCK  <> IF ." , " THEN   
     DUP EMIT  SWAP 1- SWAP
   REPEAT  DROP ;
: TEST   OVER OVER
   ." input: " TYPE CR
   ." split: " SPLIT. CR ;
s" gHHH5YY++///\"        TEST
s" gHHH5  ))YY++,,,///\" TEST
BYE
Output:
input: gHHH5YY++///\
split: g, HHH, 5, YY, ++, ///, \
input: gHHH5  ))YY++,,,///\
split: g, HHH, 5,   , )), YY, ++, ,,,, ///, \

Fortran

This is F77 style, except for the END SUBROUTINE SPLATTER which would be just END, which for F90 is also allowable outside of the MODULE protocol. Linking the start/stop markers by giving the same name is helpful, especially when the compiler checks for this. The $ symbol at the end of a FORMAT code sequence is a common F77 extension, meaning "do not finish the line" so that a later output will follow on. This is acceptable to F90 and is less blather than adding the term ,ADVANCE = "NO" inside a WRITE statement that would otherwise be required. Output is to I/O unit 6 which is the modern default for "standard output". The format code is A meaning "any number of characters" rather than A1 for "one character" so as to accommodate not just the single character from TEXT but also the two characters of ", " for the splitter between sequences. Alas, there is no provision to change fount or colour for this, to facilitate the reader's attempts to parse the resulting list especially when the text includes commas or spaces of its own. By contrast, with quoted strings, the standard protocol is to double contained quotes.

An alternative method would be to prepare the entire output in a CHARACTER variable then write that, but this means answering the maddening question "how long is a piece of string?" for that variable, though later Fortran has arrangements whereby a text variable is resized to suit on every assignment, as in TEMP = TEMP // more - but this means repeatedly copying the text to the new manifestation of the variable. Still another approach would be to prepare an array of fingers to each split point (as in Phrase_reversals#Fortran) so that the final output would be a single WRITE using that array, and again, how big must the array be? At most, as big as the number of characters in TEXT. With F90, subroutines can declare arrays of a size determined on entry, with something like INTEGER A(LEN(TEXT))

If the problem were to be solved by writing a "main line" only, there would have to be a declaration of the text variable there but since a subroutine can receive a CHARACTER variable of any size (the actual size is passed as a secret parameter), this can be dodged.

For this example a DO-loop stepping along the text is convenient, but in a larger context it would probably be most useful to work along the text with fingers L1 and L2 marking the start and finish positions of each sequence.

      SUBROUTINE SPLATTER(TEXT)	!Print a comma-separated list. Repeated characters constitute one item.
Can't display the inserted commas in a different colour so as not to look like any commas in TEXT.
       CHARACTER*(*) TEXT	!The text.
       INTEGER L	!A finger.
       CHARACTER*1 C	!A state follower.
        IF (LEN(TEXT).LE.0) RETURN	!Prevent surprises in the following..
        C = TEXT(1:1)			!Syncopation: what went before.
        DO L = 1,LEN(TEXT)	!Step through the text.
          IF (C.NE.TEXT(L:L)) THEN	!A change of character?
            C = TEXT(L:L)			!Yes. This is the new normal.
            WRITE (6,1) ", "			!Set off from what went before. This is not from TEXT.
          END IF			!So much for changes.
          WRITE (6,1) C			!Roll the current character. (=TEXT(L:L))
    1     FORMAT (A,$)			!The $ sez: do not end the line.
        END DO			!On to the next character.
        WRITE (6,1)	!Thus end the line. No output item means that the $ is not reached, so the line is ended.
      END SUBROUTINE SPLATTER	!TEXT with spaces, or worse, commas, will produce an odd-looking list.

      PROGRAM POKE
      CALL SPLATTER("gHHH5YY++///\")	!The example given.
      END

Unfortunately, the syntax highlighter has failed to notice the terminating quote character, presumably because the preceding backslash might be an "escape sequence" trigger, a facility not used in Fortran text literals except possibly as a later modernist option.

Output:
g, HHH, 5, YY, ++, ///, \

FreeBASIC

function split( instring as string ) as string
    if len(instring) < 2 then return instring
    dim as string ret = left(instring,1)
    for i as uinteger = 2 to len(instring)
        if mid(instring,i,1)<>mid(instring, i - 1, 1) then ret + = ", "
        ret += mid(instring, i, 1)
    next i
    return ret
end function

Frink

s = "gHHH5YY++///\\"
println[join[", ", map[getFunction["first", 1], s =~ %r/((.)\2*)/g]]]
Output:
g, HHH, 5, YY, ++, ///, \

FutureBasic

FB can process either Pascal strings (slowly being deprecated), or Apple's Core Foundation CFStrings (and Objective-C NSStrings). Here's the old-school Pascal string function:

local fn SplitString( inputStr as Str255 ) as Str255
Str255     resultStr
NSUInteger i

if len$( inputStr ) < 2 then resultStr = inputStr : exit fn
resultStr = left$( inputStr, 1 )
for i = 2 to len$( inputStr )
  if mid$( inputStr, i, 1 ) <> mid$( inputStr, i - 1, 1 ) then resultStr = resultStr + ", "
  resultStr = resultStr + mid$(inputStr, i, 1)
next
end fn = resultStr

window 1

print fn SplitString( "gHHH5YY++///\" )

HandleEvents

And here's the recommended CFString counterpart:

local fn SplitString( inputStr as CFStringRef ) as CFStringRef
  NSUInteger         i
  unichar            chr, lastChr = fn StringCharacterAtIndex( inputStr, 0 )
  CFMutableStringRef resultStr    = fn MutableStringWithCapacity(0)
  
  for i = 0 to len( inputStr ) - 1
    chr = fn StringCharacterAtIndex( inputStr, i )
    if ( chr != lastChr ) then MutableStringAppendString( resultStr, @", " )
    MutableStringAppendString( resultStr, mid( inputStr, i, 1 ) )
    lastChr = chr
  next
end fn = resultStr

window 1

print fn SplitString( @"gHHH5YY++///\\" )

HandleEvents

Output for either function:

g, HHH, 5, YY, ++, ///, \

Go

Treating "character" as a byte:

package main

import (
    "fmt"
    "strings"
)

func main() {
    fmt.Println(scc(`gHHH5YY++///\`))
}

func scc(s string) string {
    if len(s) < 2 {
        return s
    }
    var b strings.Builder
    p := s[0]
    b.WriteByte(p)
    for _, c := range []byte(s[1:]) {
        if c != p {
            b.WriteString(", ")
        }
        b.WriteByte(c)
        p = c
    }
    return b.String()
}
Output:
g, HHH, 5, YY, ++, ///, \


Haskell

import Data.List (group, intercalate)

main :: IO ()
main = putStrLn $ intercalate ", " (group "gHHH5YY++///\\")
Output:
g, HHH, 5, YY, ++, ///, \

or as a hand-written fold:

import Data.List (intercalate)
import Data.Bool (bool)

charGroups :: String -> [String]
charGroups =
  let go (a, b) (s, groups)
        | a == b = (b : s, groups)
        | otherwise =
            ( [a],
              bool s [b] (null s) : groups
            )
   in uncurry (:) . foldr go ([], []) . (zip <*> tail)

main :: IO ()
main =
  putStrLn $ intercalate ", " $ charGroups "gHHH5YY++///\\"
g, HHH, 5, YY, ++, ///, \

or in terms of span:

import Data.List (intercalate)

charGroups :: String -> [String]
charGroups [] = []
charGroups (c : cs) =
  let (xs, ys) = span (c ==) cs
   in (c : xs) : charGroups ys

main :: IO ()
main =
  putStrLn $ intercalate ", " $ charGroups "gHHH5YY++///\\"
Output:
g, HHH, 5, YY, ++, ///, \

IS-BASIC

100 LET S$="gHHH5YY++///\"
110 PRINT S$(1);
120 FOR I=2 TO LEN(S$)
130   IF S$(I)<>S$(I-1) THEN PRINT ", ";
140   PRINT S$(I);
150 NEXT
160 PRINT

J

Solution:

splitChars=: (1 ,~ 2 ~:/\ ]) <;.2 ]
delimitChars=: ', ' joinstring splitChars

Example Usage:

   delimitChars 'gHHH5YY++///\'
g, HHH, 5, YY, ++, ///, \

Java

You can use a regular expression to capture every character preceded by 0 or more of itself.

import java.util.regex.Matcher;
import java.util.regex.Pattern;
String split(String string) {
    Pattern pattern = Pattern.compile("(.)\\1*");
    Matcher matcher = pattern.matcher(string);
    StringBuilder strings = new StringBuilder();
    int index = 0;
    while (matcher.find()) {
        if (index++ != 0)
            strings.append(", ");
        strings.append(matcher.group());
    }
    return strings.toString();
}
g, HHH, 5, YY, ++, ///, \


An alternate demonstration

package org.rosettacode;

import java.util.ArrayList;
import java.util.List;


/**
 * This class provides a main method that will, for each arg provided,
 * transform a String into a list of sub-strings, where each contiguous
 * series of characters is made into a String, then the next, and so on,
 * and then it will output them all separated by a comma and a space.
 */
public class SplitStringByCharacterChange {
    
    public static void main(String... args){
        for (String string : args){
            
            List<String> resultStrings = splitStringByCharacter(string);
            String output = formatList(resultStrings);
            System.out.println(output);
        }
    }
    
    /**
     * @param string String - String to split
     * @return List<\String> - substrings of contiguous characters
     */
    public static List<String> splitStringByCharacter(String string){
        
        List<String> resultStrings = new ArrayList<>();
        StringBuilder currentString = new StringBuilder();
        
        for (int pointer = 0; pointer < string.length(); pointer++){
            
            currentString.append(string.charAt(pointer));
            
            if (pointer == string.length() - 1 
                    || currentString.charAt(0) != string.charAt(pointer + 1)) {
                resultStrings.add(currentString.toString());
                currentString = new StringBuilder();
            }
        }
        
        return resultStrings;
    }
    
    /**
     * @param list List<\String> - list of strings to format as a comma+space-delimited string
     * @return String
     */
    public static String formatList(List<String> list){
        
        StringBuilder output = new StringBuilder();
        
        for (int pointer = 0; pointer < list.size(); pointer++){
            output.append(list.get(pointer));
            
            if (pointer != list.size() - 1){
                output.append(", ");
            }
        }
        
        return output.toString();
    }
}
Output:
g, HHH, 5, YY, ++, ///, \

JavaScript

ES6

Translation of: Haskell
(() => {
    "use strict";

    // ----------- SPLIT ON CHARACTER CHANGES ------------
    const main = () =>
        group("gHHH5YY++///\\")
        .map(x => x.join(""))
        .join(", ");


    // --------------------- GENERIC ---------------------

    // group :: [a] -> [[a]]
    const group = xs =>
        // A list of lists, each containing only
        // elements equal under (===), such that the
        // concatenation of these lists is xs.
        groupBy(a => b => a === b)(xs);


    // groupBy :: (a -> a -> Bool) [a] -> [[a]]
    const groupBy = eqOp =>
        // A list of lists, each containing only elements
        // equal under the given equality operator,
        // such that the concatenation of these lists is xs.
        xs => 0 < xs.length ? (() => {
            const [h, ...t] = xs;
            const [groups, g] = t.reduce(
                ([gs, a], x) => eqOp(x)(a[0]) ? (
                    Tuple(gs)([...a, x])
                ) : Tuple([...gs, a])([x]),
                Tuple([])([h])
            );

            return [...groups, g];
        })() : [];


    // Tuple (,) :: a -> b -> (a, b)
    const Tuple = a =>
        b => ({
            type: "Tuple",
            "0": a,
            "1": b,
            length: 2,
            *[Symbol.iterator]() {
                for (const k in this) {
                    if (!isNaN(k)) {
                        yield this[k];
                    }
                }
            }
        });

    // MAIN ---
    return main();
})();
Output:
g, HHH, 5, YY, ++, ///, \


Or, in terms of a general `span` function:

(() => {
    "use strict";

    // -------- STRING SPLIT ON CHARACTER CHANGES --------

    // charGroups :: String -> [String]
    const charGroups = s =>
        // The characters of s split at each point where
        // consecutive characters differ.
        0 < s.length ? (() => {
            const
                c = s[0],
                [xs, ys] = span(x => c === x)([
                    ...s.slice(1)
                ]);

            return [
                    [c, ...xs], ...charGroups(ys)
                ]
                .map(zs => [...zs].join(""));
        })() : "";


    // ---------------------- TEST -----------------------
    // main :: IO()
    const main = () =>
        charGroups("gHHH5YY++///\\")
        .join(", ");


    // --------------------- GENERIC ---------------------

    // span :: (a -> Bool) -> [a] -> ([a], [a])
    const span = p =>
        // Longest prefix of xs consisting of elements which
        // all satisfy p, tupled with the remainder of xs.
        xs => {
            const i = xs.findIndex(x => !p(x));

            return -1 !== i ? [
                xs.slice(0, i),
                xs.slice(i)
            ] : [xs, []];
        };

    // MAIN ---
    return main();
})();
Output:
g, HHH, 5, YY, ++, ///, \

jq

# input: a string
# output: a stream of runs
def runs:
  def init:
    explode as $s
    | $s[0] as $i
    | (1 | until( $s[.] != $i; .+1));
  if length == 0 then empty
  elif length == 1 then .
  else init as $n | .[0:$n], (.[$n:] | runs)
  end;

"gHHH5YY++///\\" | [runs] | join(", ")
Output:

Using the -r ("raw output") command-line option of jq:

g, HHH, 5, YY, ++, ///, \

Jsish

Showing off a little unit testing...

Starting with

#!/usr/bin/env jsish
;'Split a string based on change of character, in Jsish';

function splitOnChange(str:string):string {
    if (str.length < 2) return str;
    var last = str[0];
    var result = last;
    for (var pos = 1; pos < str.length; pos++) {
        result += ((last == str[pos]) ? last : ', ' + str[pos]);
        last = str[pos];
    }
    return result;
}
provide('splitOnChange', 1.0);

/* literal backslash needs escaping during initial processing */
;splitOnChange('gHHH5YY++///\\');
;splitOnChange('a');
;splitOnChange('ab');
;splitOnChange('aaa');
;splitOnChange('aaaba');
;splitOnChange('gH HH5YY++//,/\\');

Then

prompt$ jsish -u -update true splitOnChange.jsi
Created splitOnChange.jsi

Giving

#!/usr/bin/env jsish
;'Split a string based on change of character, in Jsish';

function splitOnChange(str:string):string {
    if (str.length < 2) return str;
    var last = str[0];
    var result = last;
    for (var pos = 1; pos < str.length; pos++) {
        (last == str[pos]) ? result += last : result += ', ' + str[pos];
        last = str[pos];
    }
    return result;
}
provide('splitOnChange', 1.0);

/* literal backslash needs escaping during initial processing */
;splitOnChange('gHHH5YY++///\\');
;splitOnChange('a');
;splitOnChange('ab');
;splitOnChange('aaa');
;splitOnChange('aaaba');
;splitOnChange('gH HH5YY++//,/\\');

/*
=!EXPECTSTART!=
'Split a string based on change of character, in Jsish'
splitOnChange('gHHH5YY++///\') ==> g, HHH, 5, YY, ++, ///, \
splitOnChange('a') ==> a
splitOnChange('ab') ==> a, b
splitOnChange('aaa') ==> aaa
splitOnChange('aaaba') ==> aaa, b, a
splitOnChange('gH HH5YY++//,/\') ==> g, H,  , HH, 5, YY, ++, //, ,, /, \
=!EXPECTEND!=
*/

Which tests as:

prompt$ jsish -u splitOnChange.jsi
[PASS] splitOnChange.jsi

And then satisfying the task of showing the one result, using the script as a module:

Output:
prompt$ jsish
Jsish interactive: see 'help [cmd]'.  \ cancels > input.  ctrl-c aborts running script.
# require('splitOnChange');
1
# puts(splitOnChange('gHHH5YY++///\\'));
g, HHH, 5, YY, ++, ///, \

Julia

# v0.6
using IterTools

str = "gHHH5YY++///\\"
sep = map(join, groupby(identity, str))
println("string: $str\nseparated: ", join(sep, ", "))
Output:
string: gHHH5YY++///\
separated: g, HHH, 5, YY, ++, ///, \

K

split: {(&~=':x)_x}

","/ split "gHHH5YY++///\\"
Output:
"g,HHH,5,YY,++,///,\\"

Kotlin

// version 1.0.6

fun splitOnChange(s: String): String {
    if (s.length < 2) return s
    var t = s.take(1)  
    for (i in 1 until s.length)
        if (t.last() == s[i]) t += s[i]
        else t += ", " + s[i] 
    return t
}

fun main(args: Array<String>) {
    val s = """gHHH5YY++///\"""
    println(splitOnChange(s))
}
Output:
g, HHH, 5, YY, ++, ///, \

Using fold()

fun splitOnChange(src: String): String =
    src.fold("") { acc, c ->
        if (acc.isEmpty() || acc.last() == c) "$acc$c" else "$acc, $c"
    }

fun main() {
    splitOnChange("""gHHH5YY++///\""").also { println(it)}
}
Output:
g, HHH, 5, YY, ++, ///, \

Lambdatalk

{def mysplit
 {def mysplit.r
  {lambda {:w :i}
   {if {> :i {W.length :w}}
    then 
    else {if {not {W.equal? {W.get :i :w} {W.get {+ :i 1} :w}}}
          then ____ else} {W.get {+ :i 1} :w}{mysplit.r :w {+ :i 1}}}}}
 {lambda {:w}
  {S.replace ____ by in {mysplit.r #:w 0}}}}
-> mysplit

{mysplit gHHH5YY++///\}
->  g HHH 5 YY ++ /// \

Lua

Note that the backslash must be quoted as a double backslash as Lua uses C-like escape sequences.

function charSplit (inStr)
    local outStr, nextChar = inStr:sub(1, 1)
    for pos = 2, #inStr do
        nextChar = inStr:sub(pos, pos)
        if nextChar ~= outStr:sub(#outStr, #outStr) then
            outStr = outStr .. ", "
        end
        outStr = outStr .. nextChar
    end
    return outStr
end

print(charSplit("gHHH5YY++///\\"))
Output:
g, HHH, 5, YY, ++, ///, \

Alternative: Simply scan difference in reverse order and insert delimiter in place, the loop counter i will not update with length of s.

function splitdiff(s)
  for i=#s,2,-1 do
    if s:sub(i,i)~=s:sub(i-1,i-1) then
      s = s:sub(1,i-1)..', '.. s:sub(i,-1)
    end
  end
  return s
end

Ksh

#!/bin/ksh

# Split a character string based on change of character

#	# Variables:
#
str='gHHH5YY++///\'
delim=', '

#	# Functions:
#
#	# Function _splitonchg(str, delim) - return str split by delim at char change
#
function _splitonchg {
	typeset _str ; _str="$1"
	typeset _delim ; _delim="$2"
	typeset _i _splitstr ; integer _i

	for ((_i=1; _i<${#_str}+1; _i++)); do
		if [[ "${_str:$((_i-1)):1}" != "${_str:${_i}:1}" ]]; then
			_splitstr+="${_str:$((_i-1)):1}${_delim}"
		else
			_splitstr+="${_str:$((_i-1)):1}"
		fi
	done
	echo "${_splitstr%"${_delim}"*}"
}

 ######
# main #
 ######

print "Original: ${str}"
print "   Split: $(_splitonchg "${str}" "${delim}")"
Output:

Original: gHHH5YY++///\

Split: g, HHH, 5, YY, ++, ///, \

M2000 Interpreter

Stack New open a new stack object as current stack, and keep the old one. After the end of block execution old stack get back as current stack. Data statement push to bottom (we read from top, so using data we get a FIFO type). Letter$ pops a string or raise an error if no string found at the top of stack.

Module PrintParts(splitthis$) {
      Def string m$, p$
      Def long c
      Stack New {
            if len(splitthis$)=0 then exit
            For i=1 to len(splitthis$)
                  p$=mid$(splitthis$,i,1)
                  if m$<>p$ then {
                        if c>0 then data string$(m$, c)
                        m$=p$
                        c=1
                  } else c++
            Next i
            if c>0 then data string$(m$, c)
            While stack.size>1 {
                  Print letter$+", ";
            }
            If not empty then Print letter$
      }
}
PrintParts "gHHH5YY++///\"

Maple

Added an additional backlash to escape the \ character at the end.

splitChange := proc(str::string)
	local start,i,len;
	start := 1;
	len := StringTools:-Length(str);
	for i from 2 to len do
		if str[i] <> str[start] then
			printf("%s, ",  str[start..i-1]);
			start := i:
		end if;
	end do;
	printf("%s", str[start..len]);
end proc;
splitChange("gHHH5YY++///\\");
Output:
g, HHH, 5, YY, ++, ///, \

Mathematica/Wolfram Language

The backslash (\) must be escaped with another backslash when defining the string.

StringJoin@@Riffle[StringCases["gHHH5YY++///\\", p : (x_) .. -> p], ", "]
Output:
g, HHH, 5, YY, ++, ///, \

MiniScript

s = "gHHH5YY++///\"
output = []
lastLetter = s[0]
for letter in s
    if letter != lastLetter then output.push ", "
    output.push letter
    lastLetter = letter
end for
print output.join("")
Output:
g, HHH, 5, YY, ++, ///, \

Modula-2

MODULE CharacterChange;
FROM Terminal IMPORT Write,WriteString,WriteLn,ReadChar;

PROCEDURE Split(str : ARRAY OF CHAR);
VAR
    i : CARDINAL;
    c : CHAR;
BEGIN
    FOR i:=0 TO HIGH(str) DO
        IF i=0 THEN
            c := str[i]
        ELSIF str[i]#c THEN
            c := str[i];
            WriteLn;
        END;
        Write(c)
    END
END Split;

CONST EX = "gHHH5YY++///\";
BEGIN
    Split(EX);

    ReadChar
END CharacterChange.
Output:
g
HHH
5
YY
++
///
\

Nim

proc splitOnDiff(str: string): string =
  result = ""

  if str.len < 1: return result

  var prevChar: char = str[0]

  for idx in 0 ..< str.len:
    if str[idx] != prevChar:
      result &= ", "
      prevChar = str[idx]

    result &= str[idx]

assert splitOnDiff("""X""") == """X"""
assert splitOnDiff("""XX""") == """XX"""
assert splitOnDiff("""XY""") == """X, Y"""
assert splitOnDiff("""gHHH5YY++///\""") == """g, HHH, 5, YY, ++, ///, \"""

echo splitOnDiff("""gHHH5YY++///\""")
Output:
g, HHH, 5, YY, ++, ///, \

ooRexx

Parse Arg str  .                                  /*obtain optional arguments from the CL*/
If str=='' Then str= 'gHHH5YY++///\'        /*Not specified?  Then use the default.*/
i=1
ol=''
Do Forever
  j=verify(str,substr(str,i,1),'N',i,99)  /* find first character that's different */
  If j=0 Then Do                          /* End of strin reached                  */
    ol=ol||substr(str,i)                  /* the final substring                   */
    Leave
    End
  ol=ol||substr(str,i,j-i)', '            /* add substring and delimiter           */
  i=j
  End
Say ol
Output:
g, HHH, 5, YY, ++, ///, \

Pascal

program SplitChars;
{$IFDEF FPC}
  {$MODE DELPHI}{$COPERATORS ON}
{$ENDIF}
const
  TestString =  'gHHH5YY++///\';

function SplitAtChars(const S: String):String;
var
  i : integer;
  lastChar:Char;
begin
  result := '';
  IF length(s) > 0 then
  begin
    LastChar := s[1];
    result := LastChar;
    For i := 2 to length(s) do
    begin
      if s[i] <> lastChar then
      begin
        lastChar := s[i];
        result += ', ';
      end;
      result += LastChar;
    end;
  end;
end;

BEGIN
  writeln(SplitAtChars(TestString));
end.
Output:
g, HHH, 5, YY, ++, ///, \

Perl

use strict;
use warnings;
use feature 'say';
use utf8;
binmode(STDOUT, ':utf8');

for my $string (q[gHHH5YY++///\\], q[fffn⃗n⃗n⃗»»»  ℵℵ☄☄☃☃̂☃🤔🇺🇸🤦♂️👨‍👩‍👧‍👦]) {
    my @S;
    my $last = '';
    while ($string =~ /(\X)/g) {
        if ($last eq $1) { $S[-1] .= $1 } else { push @S, $1 }
        $last = $1;
    }
    say "Orginal: $string\n  Split: 「" . join('」, 「', @S) . "」\n";
}
Output:
Orginal: gHHH5YY++///\
  Split: 「g」, 「HHH」, 「5」, 「YY」, 「++」, 「///」, 「\」

Orginal: fffn⃗n⃗n⃗»»»  ℵℵ☄☄☃☃̂☃🤔🇺🇸🤦♂️👨‍👩‍👧‍👦
  Split: 「fff」, 「」, 「n⃗n⃗n⃗」, 「»»»」, 「  」, 「ℵℵ」, 「☄☄」, 「☃」, 「☃̂」, 「☃」, 「🤔」, 「🇺🇸」, 「🤦♂️」, 「👨‍👩‍👧‍👦」

Phix

function split_on_change(string s)
    string res = ""
    if length(s) then
        integer prev = s[1]
        for i=1 to length(s) do
            integer ch = s[i]
            if ch!=prev then
                res &= ", "
                prev = ch
            end if
            res &= ch
        end for
    end if
    return res
end function
 
puts(1,split_on_change(`gHHH5YY++///\`))
Output:
g, HHH, 5, YY, ++, ///, \

Phixmonti

/# Rosetta Code problem: https://rosettacode.org/wiki/Split_a_character_string_based_on_change_of_character
by Galileo, 11/2022 #/

include ..\Utilitys.pmt

""
"gHHH5YY++///\" 1 get >ps

len for get
    dup tps == if
        rot swap chain swap
    else
        ps> drop >ps
        swap ", " tps chain chain swap
    endif
endfor

pstack
Output:
["g, HHH, 5, YY, ++, ///, \", "gHHH5YY++///\"]

=== Press any key to exit ===

PicoLisp

(de splitme (Str)
   (let (Str (chop Str)  Fin)
      (glue
         ", "
         (make
            (for X Str
               (if (= X (car Fin))
                  (conc Fin (cons X))
                  (link (setq Fin (cons X))) ) ) ) ) ) )
(prinl (splitme "gHHH5YY++///\\"))
Output:
g, HHH, 5, YY, ++, ///, \

Pike

string input = "gHHH5YY++///\\"; // \ needs escaping
string last_char;
foreach(input/1, string char) {
    if(last_char && char != last_char)
        write(", ");
    write(char);
    last_char = char;
}
Output:
g, HHH, 5, YY, ++, ///, \

Plain English

To make sense of this example, you must understand riders. A rider is a simple abstraction for efficiently parsing strings. A rider is a record with an original substring, a source substring, and a token substring.

After executing the following code, for example:

Put "abcdef" into a string.
Slap a rider on the string.

The rider looks like this:

Original: "abcdef"
Source: "abcdef"
Token: ""

Now when we Bump the rider., it looks like this:

Original: "abcdef"
Source: "bcdef"
Token: "a"

Another bump, and:

Original: "abcdef"
Source: "cdef"
Token: "ab"

Now let's say we have a complete token and want to start a new one. We can Position the rider's token on the rider's source. and now the rider looks like this:

Original: "abcdef"
Source: "cdef"
Token: ""

And that's all there is to it.

To run:
Start up.
Split "gHHH5YY++///\" into some string things by change of character.
Write the string things on the console.
Destroy the string things.
Wait for the escape key.
Shut down.

To split a string into some string things by change of character:
If the string's length is less than 2, add the string to the string things; exit.
Slap a rider on the string.
Loop.
Move the rider (change of character rules).
Add the rider's token to the string things.
If the rider's source is blank, exit.
Repeat.

To move a rider (change of character rules):
Position the rider's token on the rider's source.
Loop.
If the rider's source is blank, exit.
If the rider's token is blank, bump the rider; repeat.
Put the rider's token's last plus 1 into a byte pointer.
If the rider's token's last's target is not the byte pointer's target, exit.
Bump the rider.
Repeat.

To write some string things to a console;
To write some string things on a console:
Get a string thing from the string things.
Loop.
If the string thing is nil, write "" on the console; exit.
Write the string thing's string on the console without advancing.
If the string thing's next is not nil, write ", " on the console without advancing.
Put the string thing's next into the string thing.
Repeat.
Output:
g, HHH, 5, YY, ++, ///, \

PowerShell

Translation of: BBC BASIC
function Split-String ([string]$String)
{
    [string]$c = $String.Substring(0,1)
    [string]$splitString = $c

    for ($i = 1; $i -lt $String.Length; $i++)
    { 
        [string]$d = $String.Substring($i,1)

        if ($d -ne $c)
        {
            $splitString += ", "
            $c = $d
        }

        $splitString += $d
    }

    $splitString
}
Split-String "gHHH5YY++///\"
Output:
g, HHH, 5, YY, ++, ///, \

PureBasic

Procedure splitstring(s$)
  Define *p.Character = @s$,
         c_buf.c = *p\c  
  While *p\c
    If *p\c = c_buf      
      Print(Chr(c_buf))
    Else
      Print(", ")
      c_buf = *p\c
      Continue
    EndIf
    *p + SizeOf(Character)
  Wend
EndProcedure

If OpenConsole()
  splitstring("gHHH5YY++///\")
  Input()
EndIf
Output:
g, HHH, 5, YY, ++, ///, \

Python

Python3.6+

Using [itertools.groupby].

from itertools import groupby

def splitter(text):
    return ', '.join(''.join(group) for key, group in groupby(text))

if __name__ == '__main__':
    txt = 'gHHH5YY++///\\'      # Note backslash is the Python escape char.
    print(f'Input: {txt}\nSplit: {splitter(txt)}')
Output:
Input: gHHH5YY++///\
Split: g, HHH, 5, YY, ++, ///, \

Python: Using zip

def splitterz(text):
    return (''.join(x + ('' if x == nxt else ', ') 
            for x, nxt in zip(txt, txt[1:] + txt[-1])))

if __name__ == '__main__':
    txt = 'gHHH5YY++///\\'
    print(splitterz(txt))
Output:
g, HHH, 5, YY, ++, ///, \

Python2

import itertools

try: input = raw_input
except: pass

s = input()
groups = []
for _, g in itertools.groupby(s):
    groups.append(''.join(g))
print('      input string:  %s' % s)
print('     output string:  %s' % ', '.join(groups))
Output:

  when using the default input

      input string:  gHHH5YY++///\
     output string:  g, HHH, 5, YY, ++, ///, \

Quackery

[ dup size 2 < 
  iff size done
  behead swap
  [] nested join
  witheach
    [ over != if 
      [ drop i^ 1+
        conclude ] ] ] is $run  ( $ --> n )

[ dup size 2 < if done
  dup $run split
  dup [] = 
  iff drop done
  dip [ $ ", " join ]
  recurse join ]       is runs$ ( $ --> $ )

Testing in Quackery shell.

/O> $ "gHHH5YY++///\" runs$ echo$
... 
g, HHH, 5, YY, ++, ///, \
Stack empty.

Racket

Translation of: Python
#lang racket
(define (split-strings-on-change s)
  (map list->string (group-by values (string->list s) char=?)))

(displayln (string-join (split-strings-on-change #<<<
gHHH5YY++///\
<
                                                 )
                        ", "))
Output:
g, HHH, 5, YY, ++, ///, \

Raku

(formerly Perl 6)

Works with: Rakudo version 2017.05
sub group-chars ($str) { $str.comb: / (.) $0* / }

# Testing:

for Q[gHHH5YY++///\], Q[fffn⃗n⃗n⃗»»»  ℵℵ☄☄☃☃̂☃🤔🇺🇸🤦‍♂️👨‍👩‍👧‍👦] -> $string {
    put 'Original: ', $string;
    put '   Split: ', group-chars($string).join(', ');
}
Output:
Original: gHHH5YY++///\
   Split: g, HHH, 5, YY, ++, ///, \
Original: fffn⃗n⃗n⃗»»»  ℵℵ☄☄☃☃̂☃🤔🇺🇸🤦‍♂️👨‍👩‍👧‍👦
   Split: fff, , n⃗n⃗n⃗, »»»,   , ℵℵ, ☄☄, ☃, ☃̂, ☃, 🤔, 🇺🇸, 🤦‍♂️, 👨‍👩‍👧‍👦

The second test-case is to show that Raku works with strings on the Unicode grapheme level, handles whitespace, combiners, and zero width characters up to Unicode Version 13.0 correctly. (Raku generally tracks updates to the Unicode spec and typically lags no more than a month behind.) For those of you with browsers unable to display the second string, it consists of:

  • {LATIN SMALL LETTER F} x 3
  • {ZERO WIDTH NO-BREAK SPACE} x 3
  • {LATIN SMALL LETTER N, COMBINING RIGHT ARROW ABOVE} x 3
  • {RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK} x 3
  • {SPACE} x 2,
  • {ALEF SYMBOL} x 2,
  • {COMET} x 2,
  • {SNOWMAN} x 1,
  • {SNOWMAN, COMBINING CIRCUMFLEX ACCENT} x 1
  • {SNOWMAN} x 1,
  • {THINKING FACE} x 1
  • {REGIONAL INDICATOR SYMBOL LETTER U, REGIONAL INDICATOR SYMBOL LETTER S} x 1
  • {FACE PALM, ZERO WIDTH JOINER, MALE SIGN, VARIATION SELECTOR-16} x 1
  • {MAN, ZERO WIDTH JOINER, WOMAN, ZERO WIDTH JOINER, GIRL, ZERO WIDTH JOINER, BOY} x 1

REXX

version 1

/*REXX program splits a string based on change of character ───► a comma delimited list.*/
parse arg str                                    /*obtain optional arguments from the CL*/
if str==''  then str= 'gHHH5YY++///\'            /*Not specified?  Then use the default.*/
p=left(str, 1)                                   /*placeholder for the "previous" string*/
$=                                               /*     "       "   "    output      "  */
     do j=1  for length(str);  @=substr(str,j,1) /*obtain a character from the string.  */
     if @\==p  then $=$', '                      /*Not replicated char? Append delimiter*/
     p=@;           $=$ || @                     /*append a character to the  $  string.*/
     end   /*j*/                                 /* [↓]  keep peeling chars until done. */
say '          input string: '      str          /*display the original string & output.*/
say '         output string: '      $            /*stick a fork in it,  we're all done. */
output   when using the default input:
          input string:  gHHH5YY++///\
         output string:  g, HHH, 5, YY, ++, ///, \

version 2

/* REXX */
Parse arg str                         /*obtain optional arguments from the CL*/
if str==''  then str= 'gHHH5YY++///\' /*Not specified?  Then use the default.*/
input=str
x=''
cp=''
result=''
Do While str<>''
  Parse Var str c +1 str
  If c==cp Then x=x||c
  Else Do
    If x>>'' Then
      result=result||x', '
    x=c
    End
  cp=c
  End
result=result||x
say '      input string: '    input
say '     output string: '    result

{{out]]

      input string:  gHHH5YY++///\
     output string:  g, HHH, 5, YY, ++, ///, \

Ring

see split("gHHH5YY++///\")

func split(s )
     c =left (s, 1)
     split = ""
     for i = 1 to len(s)
         d = substr(s, i, 1)
         if d != c
            split = split + ", "
            c = d 
         ok
         split = split + d 
     next
     return split

Output:

g, HHH, 5, YY, ++, ///, \

RPL

≪ → text
   ≪ "" text 1 1 SUB
      1 text SIZE FOR j
        text j DUP SUB 
        IF DUP2 ≠ THEN SWAP DROP ", " OVER + END
        ROT SWAP + SWAP
      NEXT DROP
≫ ≫ ‘COMASPLT’ STO

Ruby

def split(str)
  puts " input string: #{str}"
  s = str.chars.chunk(&:itself).map{|_,a| a.join}.join(", ")
  puts "output string: #{s}"
  s
end

split("gHHH5YY++///\\")
Output:
 input string: gHHH5YY++///\
output string: g, HHH, 5, YY, ++, ///, \

Rust

fn splitter(string: &str) -> String {
    let chars: Vec<_> = string.chars().collect();
    let mut result = Vec::new();
    let mut last_mismatch = 0;
    for i in 0..chars.len() {
        if chars.len() == 1 {
            return chars[0..1].iter().collect();
        }
        if i > 0 && chars[i-1] != chars[i] {
            let temp_result: String = chars[last_mismatch..i].iter().collect();
            result.push(temp_result);
            last_mismatch = i;
        }
        if i == chars.len() - 1 {
            let temp_result: String = chars[last_mismatch..chars.len()].iter().collect();
            result.push(temp_result);
        }
    }
    result.join(", ")
}

fn main() {
    let test_string = "g";
    println!("input string: {}", test_string);
    println!("output string: {}", splitter(test_string));

    let test_string = "";
    println!("input string: {}", test_string);
    println!("output string: {}", splitter(test_string));

    let test_string = "gHHH5YY++///\\";
    println!("input string: {}", test_string);
    println!("output string: {}", splitter(test_string));
}
Output:
input string: g
output string: g
input string: 
output string: 
input string: gHHH5YY++///\
output string: g, HHH, 5, YY, ++, ///, \

Alternate using IterTools

use itertools::Itertools;

pub fn split_text(s: &str) -> Vec<String> {
    let mut r = Vec::new();
    for (_, group) in &s.chars().into_iter().group_by(|e| *e) {
        r.push(group.map(|e| e.to_string()).join(""));
    }
    r
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_splitting_text() {
        assert_eq!(split_text("gHHH5YY++///\\"), vec!["g", "HHH", "5", "YY", "++", "///", "\\"]);
        assert!(split_text("").is_empty());
    }
}

Scala

// Split a (character) string into comma (plus a blank) delimited strings
// based on a change of character (left to right).
// See https://rosettacode.org/wiki/Split_a_character_string_based_on_change_of_character#Scala

def runLengthSplit(s: String): String = /// Add a guard letter
  (s + 'X').sliding(2).map(pair => pair.head + (if (pair.head != pair.last) ", " else "")).mkString("")

println(runLengthSplit("""gHHH5YY++///\"""))
Output:

See it in running in your browser by ScalaFiddle (JavaScript)

or by Scastie (JVM).

def runLengthSplit(s:String):List[String] = {
  def recursiveSplit(acc:List[String], rest:String): List[String] = rest match {
    case "" => acc
    case _ => {
      val (h, t) = rest.span(_ == rest.head)
      recursiveSplit(acc :+ h, t)
    }
  }

  recursiveSplit(Nil, s)
}

val result = runLengthSplit("""gHHH5YY++///\""")
println(result.mkString(","))
Output:
g,HHH,5,YY,++,///,\

Sed

echo 'gHHH5YY++///\' | sed 's/\(.\)\1*/&, /g;s/, $//'

Output:

g, HHH, 5, YY, ++, ///, \

Sidef

func group(str) {
    gather {
        while (var match = (str =~ /((.)\g{-1}*)/g)) {
            take(match[0])
        }
    }
}

say group(ARGV[0] \\ 'gHHH5YY++///\\').join(', ')
Output:
g, HHH, 5, YY, ++, ///, \

SNOBOL4

* Program: split_on_change_of_character.sbl
* To run: sbl split_on_change_of_character.sbl
* Description: Split a (character) string into comma (plus a blank)
* delimited strings based on a change of character   (left to right).
*
* Blanks should be treated as any other character
* (except they are problematic to display clearly).
* The same applies to commas.
*
* For instance, the string:
*
* gHHH5YY++///\ 
* should be split and show:
*
* g, HHH, 5, YY, ++, ///, \ 
* Comment: Tested using the Spitbol for Linux version of SNOBOL4

	lf = substr(&alphabet,11,1) ;* New line or line feed

* Function split_cc will split a string on a change of character.
	define('split_cc(s)tchar,target,post')
	:(split_cc_end)
split_cc
	tchar = substr(s,1,1) :f(freturn)
	split_cc_pat = span(*tchar) . target (rpos(0) | len(1) . tchar rem) . post
split_cc2
	s ? split_cc_pat = post :f(split_cc3)
	split_cc = (ident(split_cc) target, split_cc ', ' target) :s(split_cc2)
split_cc3
	:(return)
split_cc_end

	test_string = "gHHH5YY++///\"
	output = test_string lf
	split_string = split_cc(test_string)
	output = split_string

END
Output:
gHHH5YY++///\

g, HHH, 5, YY, ++, ///, \

Standard ML

(*
 * Head-Tail implementation of grouping
 *)
fun group'     ac      nil = [ac]
  | group'     nil (y::ys) = group' [y] ys
  | group' (x::ac) (y::ys) = if x=y then group' (y::x::ac) ys else (x::ac) :: group' [y] ys

fun group xs = group' nil xs

fun groupString str = String.concatWith ", " (map implode (group (explode str)))
Output:
- groupString "gHHH5YY++///\\";
val it = "g, HHH, 5, YY, ++, ///, \\" : string

Swift

public extension String {
  func splitOnChanges() -> [String] {
    guard !isEmpty else {
      return []
    }

    var res = [String]()
    var workingChar = first!
    var workingStr = "\(workingChar)"

    for char in dropFirst() {
      if char != workingChar {
        res.append(workingStr)
        workingStr = "\(char)"
        workingChar = char
      } else {
        workingStr += String(char)
      }
    }

    res.append(workingStr)

    return res
  }
}

print("gHHH5YY++///\\".splitOnChanges().joined(separator: ", "))
Output:
g, HHH, 5, YY, ++, ///, \

Tailspin

composer splitEquals
  <reps> <nextReps>*
  rule reps: <'(.)\1*'>
  rule nextReps: <reps> -> \(', ' ! $ ! \)
end splitEquals

'gHHH5YY++///\' -> splitEquals -> !OUT::write
Output:
g, HHH, 5, YY, ++, ///, \

tbas

Translation of: BBC BASIC
SUB SPLITUNIQUE$(s$)
	DIM c$, d$, split$, i%
	c$ = LEFT$(s$, 1)
	split$ = ""
	FOR i% = 1 TO LEN(s$)
	  d$ = MID$(s$, i%, 1)
	  IF d$ <> c$ THEN
		split$ = split$ + ", "
		c$ = d$
	  END IF
	  split$ = split$ + d$
	NEXT
	RETURN split$
END SUB

PRINT SPLITUNIQUE$("gHHH5YY++///\")
END

Tcl

This is most concise with regular expressions. Note well the two steps: it could be achieved in one very clever regexp, but being that clever is usually a bad idea (for both readability and performance, in this case).

set string "gHHH5YY++///\\"

regsub -all {(.)\1*} $string {\0, } string
regsub {, $} $string {} string
puts $string
Output:
g, HHH, 5, YY, ++, ///, \

Transd

The task doesn't state explicitly about the order in which substrings should be displayed. So, here are two variants: one is order-preserving, the other is not order-preserving.

#lang transd

MainModule: {
    s: "gHHH5YY++///\\",
    _start: (λ
        (with res ""
            (for c in (split s "") do
                (if (neq Char(c) (back res)) (+= res ", "))
                (+= res c))
            (textout res))

        (lout "Second variant: ")

        (for v in (values (group-by (split s ""))) do
            (textout (if @idx ", ") (join v "")))
    )
}
Output:
g, HHH, 5, YY, ++, ///, \
Second variant:
++, ///, 5, HHH, YY, \, g

VBA

Option Explicit

Sub Split_string_based_on_change_character()
Dim myArr() As String, T As String

Const STRINPUT As String = "gHHH5YY++///\"
Const SEP As String = ", "
    
    myArr = Split_Special(STRINPUT)
    T = Join(myArr, SEP)
    Debug.Print Left(T, Len(T) - Len(SEP))
End Sub

Function Split_Special(Ch As String) As String()
'return an array of Strings
Dim tb, i&, st As String, cpt As Long, R() As String

    tb = Split(StrConv(Ch, vbUnicode), Chr(0))
    st = tb(LBound(tb))
    ReDim R(cpt)
    R(cpt) = st
    For i = 1 To UBound(tb)
        If tb(i) = st Then
            R(cpt) = R(cpt) & st
        Else
            st = tb(i)
            cpt = cpt + 1
            ReDim Preserve R(cpt)
            R(cpt) = st
        End If
    Next
    Split_Special = R
End Function
Output:
g, HHH, 5, YY, ++, ///, \

V (Vlang)

fn main() {
	println(splitter('gHHH5YY++///\\')) \\ The "\" character needs to be escaped.
}

fn splitter(text string) string {
	mut check := text.substr(0, 1)
	mut new_text, mut temp := '', ''
	for index, _ in text {
		temp = text.substr(index, index + 1)
		if temp != check {
			new_text = new_text + ', '
			check = temp 
		}
		new_text = new_text + temp 
	}
	return new_text
}
Output:
g, HHH, 5, YY, ++, ///, \

Wren

var split = Fn.new { |s|
    if (s.count == 0) return ""
    var res = []
    var last = s[0]
    var curr = last
    for (c in s.skip(1)) {
        if (c == last) {
            curr = curr + c
        } else {
            res.add(curr)
            curr = c
        }
        last = c
    }
    res.add(curr)
    return res.join(", ")
}

var s = "gHHH5YY++///\\" 
System.print(split.call(s))
Output:
g, HHH, 5, YY, ++, ///, \

XLISP

(defun delimit (s)
	(defun delim (old-list new-list current-char)
		(if (null old-list)
			new-list
			(delim (cdr old-list) (append new-list
				(if (not (equal (car old-list) current-char))
					`(#\, #\Space ,(car old-list))
					(cons (car old-list) nil) ) )
			(car old-list) ) ) )
	(list->string (delim (string->list s) '() (car (string->list s)))) )

(display (delimit "gHHH5YY++///\\")) ;; NB. The "\" character needs to be escaped
Output:
g, HHH, 5, YY, ++, ///, \

XPL0

string 0;       \change to zero-terminated convention
char S;
[S:= "gHHH5YY++///\";
while S(0) do
        [ChOut(0, S(0));
        if S(1)#S(0) & S(1)#0 then Text(0, ", ");
        S:= S+1;
        ];
]
Output:
g, HHH, 5, YY, ++, ///, \

Yabasic

sub esplit$(instring$)
	if len(instring$) < 2 return instring$
    ret$ = left$(instring$,1)
    for i = 2 to len(instring$)
	if mid$(instring$,i,1) <> mid$(instring$, i - 1, 1) ret$ = ret$ + ", "
        ret$ = ret$ + mid$(instring$, i, 1)
    next i
   return ret$
end sub

print esplit$("gHHH5YY++///\\")

Z80 Assembly

PrintChar equ &BB5A ;Amstrad CPC BIOS call
Terminator equ 0    ;marks the end of a string
        org &8000

	LD HL,StringA
loop:
	ld a,(HL)		;load a char from (HL)
	cp Terminator	        ;is it the terminator?
	ret z			;if so, exit
	ld e,a			;store this char in E temporarily
	inc hl			;next char
	ld a,(HL)		;get next char
	cp Terminator	        ;is the next char the terminator?
	jp z,StringDone	        ;if so, print E and exit.

	;needed to prevent the last char from getting a comma and space.
	
	dec hl			;go back one so we don't skip any chars
	cp e                    ;does (HL) == (HL+1)?
	
	push af
	ld a,e
	call PrintChar		;either way, print E to screen.
	pop af			;retrieve the results of the last compare.
	
	jr z,SkipComma		;if A=E, no comma or space. Just loop again.
	ld a,','
	call PrintChar
	ld a,' '
	call PrintChar
SkipComma:
	inc hl			;next char
	jp loop			;back to start
StringDone:
	ld a,e			;last character in string is printed here.
	jp PrintChar
	
ReturnToBasic:
	RET
	

StringA:
	byte "gHHH5YY++///\",0
Output:
g, HHH, 5, YY, ++, ///, \

zkl

fcn group(str){
   C,out := str[0],Sink(C);
   foreach c in (str[1,*]){ out.write(if(c==C) c else String(", ",C=c)) }
   out.close();
}
group("gHHH5YY++///\\").println();
Output:
g, HHH, 5, YY, ++, ///, \

ZX Spectrum Basic

 10 LET s$="gHHH5YY++///\"
 20 LET c$=s$(1)
 30 LET n$=c$
 40 FOR i=2 TO LEN s$
 50 IF s$(i)<>c$ THEN LET n$=n$+", "
 60 LET n$=n$+s$(i)
 70 LET c$=s$(i)
 80 NEXT i
 90 PRINT n$
Output:
g, HHH, 5, YY, ++, ///, \