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

m
→‎{{header|Wren}}: Changed to Wren S/H
(Added 11l)
m (→‎{{header|Wren}}: Changed to Wren S/H)
 
(63 intermediate revisions by 32 users not shown)
Line 1:
[[Category: String manipulation]]
[[Category:Strings]]
[[Category:Simple]]
{{task}}
Line 24 ⟶ 25:
 
 
{{Template:Strings}}
;Related task:
*   [[Tokenize a string with escaping]]
<br><br>
 
=={{header|11l}}==
{{trans|C++}}
 
<langsyntaxhighlight lang="11l">F split(input, delim)
V res = ‘’
L(ch) input
Line 38 ⟶ 39:
R res
 
print(split(‘gHHH5YY++///\’, ‘, ’))</langsyntaxhighlight>
 
{{out}}
Line 44 ⟶ 45:
g, HHH, 5, YY, ++, ///, \
</pre>
 
=={{header|8080 Assembly}}==
<syntaxhighlight lang="8080asm"> 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 $</syntaxhighlight>
{{out}}
<pre>g, HHH, 5, YY, ++, ///, \</pre>
 
=={{header|8086 Assembly}}==
<syntaxhighlight lang="asm"> 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</syntaxhighlight>
{{out}}
<pre>g, HHH, 5, YY, ++, ///, \</pre>
 
=={{header|AArch64 Assembly}}==
{{works with|as|Raspberry Pi 3B version Buster 64 bits}}
<syntaxhighlight lang="aarch64 assembly">
<lang AArch64 Assembly>
/* ARM assembly AARCH64 Raspberry PI 3B */
/* program splitcar64.s */
Line 146 ⟶ 219:
/* for this file see task include a file in language AArch64 assembly */
.include "../includeARM64.inc"
</syntaxhighlight>
</lang>
{{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}}==
<langsyntaxhighlight lang="ada">
with Ada.Text_IO;
procedure Split is
Line 167 ⟶ 280:
Print_Tokens ("gHHH5YY+++");
end split;
</syntaxhighlight>
</lang>
 
=={{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 #
PROC split on characters = ( STRING s )STRING:
Line 182 ⟶ 294:
[ 3 * ( ( UPB s - LWB s ) + 1 ) ]CHAR result;
INT r pos := LWB result;
INT s pos := LWB s;
CHAR s char := s[ LWB s ];
FOR s pos FROM LWB s TO UPB s DO
Line 200 ⟶ 311:
 
print( ( split on characters( "gHHH5YY++///\" ), newline ) )
END</langsyntaxhighlight>
{{out}}
<pre>
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>
 
=={{header|ANSI BASIC}}==
{{works with|Decimal BASIC}}
<lang ansibasic>REM >split
<syntaxhighlight lang="basic">REM >split
DECLARE EXTERNAL FUNCTION FN_split$
 
Line 225 ⟶ 404:
NEXT i
LET FN_split$ = split$
END FUNCTION</langsyntaxhighlight>
{{out}}
<pre>g, HHH, 5, YY, ++, ///, \</pre>
 
=={{header|APL}}==
{{works with|Dyalog APL}}
<syntaxhighlight lang="apl">split ← 2↓∘∊(⊂', '),¨(⊢≠¯1⌽⊢)⊂⊢</syntaxhighlight>
{{out}}
<pre> split 'gHHH5YY++///\'
g, HHH, 5, YY, ++, ///, \</pre>
 
=={{header|AppleScript}}==
===Functional===
{{Trans|JavaScript}}
<langsyntaxhighlight AppleScriptlang="applescript">intercalate(", ", ¬
map(curry(intercalate)'s |λ|(""), ¬
group("gHHH5YY++///\\")))
Line 348 ⟶ 534:
{}
end if
end tail</langsyntaxhighlight>
{{Out}}
<pre>g, HHH, 5, YY, ++, ///, \</pre>
Line 354 ⟶ 540:
===Straightforward===
(Also case-sensitve.)
<langsyntaxhighlight lang="applescript">on splitAtCharacterChanges(input)
set len to (count input)
if (len < 2) then return input
Line 377 ⟶ 563:
 
-- Test code:
splitAtCharacterChanges("gHHH5YY++///\\")</langsyntaxhighlight>
 
{{output}}
<langsyntaxhighlight lang="applescript">"g, HHH, 5, YY, ++, ///, \\"</langsyntaxhighlight>
 
===ASObjC===
 
<langsyntaxhighlight lang="applescript">use AppleScript version "2.4" -- OS X 10.10 (Yosemite) or later
use framework "Foundation"
 
Line 394 ⟶ 580:
 
-- Test code:
splitAtCharacterChanges("gHHH5YY++///\\")</langsyntaxhighlight>
 
{{output}}
<langsyntaxhighlight lang="applescript">"g, HHH, 5, YY, ++, ///, \\"</langsyntaxhighlight>
 
=={{header|ARM Assembly}}==
Line 403 ⟶ 589:
 
{{works with|as|Raspberry Pi}}
<syntaxhighlight lang="arm assembly">
<lang ARM Assembly>
/* ARM assembly Raspberry PI */
/* program splitcar.s */
Line 521 ⟶ 707:
 
output : gg, HHH, 5, YY, ++, ///, \
</syntaxhighlight>
</lang>
 
=={{header|Arturo}}==
<langsyntaxhighlight lang="rebol">parts: [] current: ""
loop split {gHHH5YY++///\} 'ch [
if? or? empty? current
Line 534 ⟶ 720:
]
'parts ++ current
print parts</langsyntaxhighlight>
 
{{out}}
Line 541 ⟶ 727:
 
=={{header|AutoHotkey}}==
<langsyntaxhighlight AutoHotkeylang="autohotkey">Split_Change(str){
for i, v in StrSplit(str)
res .= (v=prev) ? v : (res?", " :"") v , prev := v
return res
}</langsyntaxhighlight>
Examples:<langsyntaxhighlight AutoHotkeylang="autohotkey">str := "gHHH5YY++///\"
MsgBox % Split_Change(str)</langsyntaxhighlight>
Outputs:<pre>g, HHH, 5, YY, ++, ///, \</pre>
===RegEx Version===
<langsyntaxhighlight AutoHotkeylang="autohotkey">Split_Change(str){
return RegExReplace(str, "(.)\1*(?!$)", "$0, ")
}</langsyntaxhighlight>
Examples:<langsyntaxhighlight AutoHotkeylang="autohotkey">str := "gHHH5YY++///\"
MsgBox % Split_Change(str)</langsyntaxhighlight>
Outputs:<pre>g, HHH, 5, YY, ++, ///, \</pre>
 
=={{header|AWK}}==
<syntaxhighlight lang="awk">
<lang AWK>
# syntax: GAWK -f SPLIT_A_CHARACTER_STRING_BASED_ON_CHANGE_OF_CHARACTER.AWK
BEGIN {
Line 577 ⟶ 763:
return(new_str)
}
</syntaxhighlight>
</lang>
{{out}}
<pre>
Line 586 ⟶ 772:
=={{header|BaCon}}==
Literal strings in BaCon are passed to the C compiler as they are; a backslash therefore needs to be escaped.
<langsyntaxhighlight lang="freebasic">txt$ = "gHHH5YY++///\\"
 
c$ = LEFT$(txt$, 1)
Line 597 ⟶ 783:
END IF
PRINT d$;
NEXT</langsyntaxhighlight>
{{out}}
<pre>
g, HHH, 5, YY, ++, ///, \
</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}}==
<langsyntaxhighlight lang="bbcbasic">REM >split
PRINT FN_split( "gHHH5YY++///\" )
END
Line 620 ⟶ 819:
split$ += d$
NEXT
= split$</langsyntaxhighlight>
{{out}}
<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}}==
<langsyntaxhighlight lang="c">#include <stdio.h>
#include <stdlib.h>
#include <string.h>
Line 648 ⟶ 855:
*(counter--)='\0';
return realloc(result,strlen(result));
}</langsyntaxhighlight>
{{out}}
<pre>
Line 655 ⟶ 862:
 
=={{header|C sharp}}==
<langsyntaxhighlight lang="csharp">using System;
using System.Linq;
using System.Collections.Generic;
Line 686 ⟶ 893:
 
public static string Delimit<T>(this IEnumerable<T> source, string separator = "") => string.Join(separator ?? "", source);
}</langsyntaxhighlight>
{{out}}
<pre>
Line 693 ⟶ 900:
 
=={{header|C++}}==
<langsyntaxhighlight lang="cpp">
// Solution for http://rosettacode.org/wiki/Split_a_character_string_based_on_change_of_character
#include<string>
Line 710 ⟶ 917:
int main(){
std::cout << split("gHHH5 ))YY++,,,///\\", ", ") << std::endl;
}</langsyntaxhighlight>
{{out}}
<pre>g, HHH, 5, , )), YY, ++, ,,,, ///, \</pre>
 
=={{header|Clojure}}==
<langsyntaxhighlight lang="clojure">(defn print-cchanges [s]
(println (clojure.string/join ", " (map first (re-seq #"(.)\1*" s)))))
 
(print-cchanges "gHHH5YY++///\\")
</syntaxhighlight>
</lang>
{{out}}
<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}}==
<syntaxhighlight lang="cobol">
<lang COBOL>
identification division.
program-id. split-ch.
Line 786 ⟶ 1,025:
 
end program split-ch.
</syntaxhighlight>
</lang>
{{out}}
<pre>
Line 800 ⟶ 1,039:
=={{header|Common Lisp}}==
 
<langsyntaxhighlight lang="lisp">(defun split (string)
(loop :for prev := nil :then c
:for c :across string
Line 806 ⟶ 1,045:
 
(split "gHHH5YY++///\\")
</syntaxhighlight>
</lang>
{{out}}
<pre>g, HHH, 5, YY, ++, ///, \</pre>
Line 812 ⟶ 1,051:
Doing more work that what's being ask, the following solution builds a list of strings then output it:
 
<langsyntaxhighlight lang="lisp">(defun split (string)
(flet ((make-buffer ()
(make-array 0 :element-type 'character :adjustable t :fill-pointer t)))
Line 826 ⟶ 1,065:
(format t "~{~A~^, ~}"(nreverse result)))))
 
(split "gHHH5YY++///\\")</langsyntaxhighlight>
{{out}}
<pre>g, HHH, 5, YY, ++, ///, \</pre>
 
=={{header|Cowgol}}==
<syntaxhighlight lang="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();</syntaxhighlight>
{{out}}
<pre>g, HHH, 5, YY, ++, //, \</pre>
 
=={{header|D}}==
 
<langsyntaxhighlight Dlang="d">import std.stdio;
 
void main() {
Line 846 ⟶ 1,110:
}
writeln();
}</langsyntaxhighlight>
 
{{output}}
<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}}==
 
<langsyntaxhighlight lang="dyalect">func String.smartSplitSmartSplit() {
var c
var str = ""
var last = this.lenLength() - 1
 
for n in 0..last {
if c && this[n] != c {
Line 865 ⟶ 1,170:
str += c
}
 
str
}
 
print("gHHH5YY++///\\".smartSplitSmartSplit())</langsyntaxhighlight>
 
{{out}}
Line 877 ⟶ 1,182:
=={{header|EasyLang}}==
 
<syntaxhighlight lang="text">
<lang>a$ = "gHHH5YY++///\"
a$[] = str_chars a$"gHHH5YY++///\\"
ca$[] = strchars a$[0]
for i rangecp$ len= a$[1]
for c$ ifin a$[i] <> c$
if bc$ &=<> ", "cp$
c s$ &= a$[i]", "
cp$ = c$
.
b$ &= a$[i].
s$ &= c$
.
print bs$</lang>
</syntaxhighlight>
{{out}}
<pre>
Line 894 ⟶ 1,201:
 
=={{header|Elixir}}==
<langsyntaxhighlight lang="elixir">split = fn str ->
IO.puts " input string: #{str}"
String.graphemes(str)
Line 902 ⟶ 1,209:
end
 
split.("gHHH5YY++///\\")</langsyntaxhighlight>
 
{{out}}
Line 911 ⟶ 1,218:
 
=={{header|F_Sharp|F#}}==
<langsyntaxhighlight lang="fsharp">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++///\""")</langsyntaxhighlight>
{{out}}
<pre>["g"; "HHH"; "5"; "YY"; "++"; "///"; "\"]</pre>
 
=={{header|Factor}}==
<langsyntaxhighlight lang="factor">USE: splitting.monotonic
"gHHH5YY++///\\"
"aaabbccccdeeff" [ [ = ] monotonic-split ", " join print ] bi@</langsyntaxhighlight>
{{out}}
<pre>
Line 929 ⟶ 1,236:
=={{header|Forth}}==
{{works with|Gforth|0.7.3}}
<langsyntaxhighlight Forthlang="forth">CREATE A 0 ,
: C@A+ A @ C@ [ 1 CHARS ]L A +! ;
: SPLIT. ( c-addr u --) SWAP A ! A @ C@
Line 941 ⟶ 1,248:
s" gHHH5YY++///\" TEST
s" gHHH5 ))YY++,,,///\" TEST
BYE</langsyntaxhighlight>
{{out}}
<pre>input: gHHH5YY++///\
Line 955 ⟶ 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.
 
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. <langsyntaxhighlight Fortranlang="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.
CHARACTER*(*) TEXT !The text.
Line 975 ⟶ 1,282:
PROGRAM POKE
CALL SPLATTER("gHHH5YY++///\") !The example given.
END</langsyntaxhighlight>
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.
 
{{Out}}
<pre>
g, HHH, 5, YY, ++, ///, \
</pre>
 
=={{header|FreeBASIC}}==
<syntaxhighlight lang="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</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, ++, ///, \
Line 985 ⟶ 1,358:
=={{header|Go}}==
Treating "character" as a byte:
<langsyntaxhighlight lang="go">package main
 
import (
Line 1,011 ⟶ 1,384:
}
return b.String()
}</langsyntaxhighlight>
{{out}}
<pre>
g, HHH, 5, YY, ++, ///, \
</pre>
 
 
=={{header|Haskell}}==
 
<langsyntaxhighlight Haskelllang="haskell">import Data.List (group, intercalate)
 
main :: IO ()
main = putStrLn $ intercalate ", " (group "gHHH5YY++///\\")</langsyntaxhighlight>
 
{{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}}
<pre>g, HHH, 5, YY, ++, ///, \</pre>
 
=={{header|IS-BASIC}}==
<langsyntaxhighlight ISlang="is-BASICbasic">100 LET S$="gHHH5YY++///\"
110 PRINT S$(1);
120 FOR I=2 TO LEN(S$)
Line 1,034 ⟶ 1,442:
140 PRINT S$(I);
150 NEXT
160 PRINT</langsyntaxhighlight>
 
=={{header|J}}==
'''Solution:'''
<langsyntaxhighlight lang="j">splitChars=: (1 ,~ 2 ~:/\ ]) <;.2 ]
delimitChars=: ', ' joinstring splitChars</langsyntaxhighlight>
'''Example Usage:'''
<langsyntaxhighlight lang="j"> delimitChars 'gHHH5YY++///\'
g, HHH, 5, YY, ++, ///, \</langsyntaxhighlight>
 
=={{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;
Line 1,110 ⟶ 1,541:
return output.toString();
}
}</langsyntaxhighlight>
 
{{Out}}
Line 1,118 ⟶ 1,549:
===ES6===
{{Trans|Haskell}}
<langsyntaxhighlight JavaScriptlang="javascript">(() => {
"use strict";
// GENERIC FUNCTIONS ------------------------------------------------------
 
// ----------- SPLIT ON CHARACTER CHANGES ------------
// concat :: [[a]] -> [a] | [String] -> String
const concatmain = xs() =>
xs.length > 0 ? (group("gHHH5YY++///\\") => {
.map(x => x.join(""))
const unit = typeof xs[0] === 'string' ? '' : [];
return unit.concat.applyjoin(unit", xs");
 
 
// --------------------- 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];
})() : [];
 
// group :: Eq a => [a] -> [[a]]
const group = xs => groupBy((a, b) => a === b, xs);
 
// groupByTuple (,) :: (a -> ab -> Bool) -> [(a], -> [[a]]b)
const groupByTuple = (f, xs)a => {
const dctb => xs.slice(1){
.reduce((atype: "Tuple", x) => {
"0": consta,
h = a.active.length > 0 ? a.active[0] "1": undefinedb,
length: blnGroup = h !== undefined && f(h2, x);
return*[Symbol.iterator]() {
for (const k in active: blnGroup ? a.active.concat([x]this) : [x],{
sofar:if blnGroup ? a.sofar : a.sofar.concat([a.active]!isNaN(k)) {
} yield this[k];
}, { }
active: xs.length > 0 ? [xs[0]] : [],}
sofar: []}
});
 
return dct.sofar.concat(dct.active.length > 0 ? [dct.active] : []);
};// MAIN ---
return main();
})();</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(""));
})() : "";
 
// intercalate :: String -> [a] -> String
const intercalate = (s, xs) => xs.join(s);
 
// ---------------------- TEST -----------------------
// map :: (a -> b) -> [a] -> [b]
const// mapmain =:: IO(f, xs) => xs.map(f);
const main = () =>
charGroups("gHHH5YY++///\\")
.join(", ");
 
// show :: a -> String
const show = (...x) =>
JSON.stringify.apply(
null, x.length > 1 ? [x[0], null, x[1]] : x
);
 
// --------------------- GENERIC ---------------------
// stringChars :: String -> [Char]
const stringChars = s => s.split('');
 
// 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 ? [
// TEST -------------------------------------------------------------------
xs.slice(0, i),
return show(
intercalate(', ', xs.slice(i)
map(concat] : [xs, group(stringChars('gHHH5YY++///\\')))[]];
)};
);
 
// MAIN ---
// -> "g, HHH, 5, YY, ++, ///, \\"
return main();
})();</lang>
})();</syntaxhighlight>
{{Out}}
<pre>g, HHH, 5, YY, ++, ///, \</pre>
 
=={{header|jq}}==
<langsyntaxhighlight lang="jq"># input: a string
# output: a stream of runs
def runs:
Line 1,190 ⟶ 1,675:
end;
 
"gHHH5YY++///\\" | [runs] | join(", ")</langsyntaxhighlight>
{{out}}
Using the -r ("raw output") command-line option of jq:
Line 1,199 ⟶ 1,684:
 
Starting with
<langsyntaxhighlight lang="javascript">#!/usr/bin/env jsish
;'Split a string based on change of character, in Jsish';
 
Line 1,220 ⟶ 1,705:
;splitOnChange('aaa');
;splitOnChange('aaaba');
;splitOnChange('gH HH5YY++//,/\\');</langsyntaxhighlight>
 
Then
Line 1,229 ⟶ 1,714:
Giving
 
<langsyntaxhighlight lang="javascript">#!/usr/bin/env jsish
;'Split a string based on change of character, in Jsish';
 
Line 1,262 ⟶ 1,747:
splitOnChange('gH HH5YY++//,/\') ==> g, H, , HH, 5, YY, ++, //, ,, /, \
=!EXPECTEND!=
*/</langsyntaxhighlight>
 
Which tests as:
Line 1,280 ⟶ 1,765:
 
=={{header|Julia}}==
<langsyntaxhighlight lang="julia"># v0.6
using IterTools
 
str = "gHHH5YY++///\\"
sep = map(join, groupby(identity, str))
println("string: $str\nseparated: ", join(sep, ", "))</langsyntaxhighlight>
 
{{out}}
<pre>string: gHHH5YY++///\
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}}==
<langsyntaxhighlight scalalang="kotlin">// version 1.0.6
 
fun splitOnChange(s: String): String {
Line 1,306 ⟶ 1,798:
val s = """gHHH5YY++///\"""
println(splitOnChange(s))
}</langsyntaxhighlight>
{{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}}
<pre>
Line 1,314 ⟶ 1,822:
 
=={{header|Lambdatalk}}==
<langsyntaxhighlight lang="scheme">
{def mysplit
{def mysplit.r
Line 1,328 ⟶ 1,836:
{mysplit gHHH5YY++///\}
-> g HHH 5 YY ++ /// \
</syntaxhighlight>
</lang>
 
=={{header|Lua}}==
Note that the backslash must be quoted as a double backslash as Lua uses C-like escape sequences.
<langsyntaxhighlight Lualang="lua">function charSplit (inStr)
local outStr, nextChar = inStr:sub(1, 1)
for pos = 2, #inStr do
Line 1,344 ⟶ 1,852:
end
 
print(charSplit("gHHH5YY++///\\"))</langsyntaxhighlight>
{{out}}
<pre>g, HHH, 5, YY, ++, ///, \</pre>
Line 1,350 ⟶ 1,858:
'''Alternative:'''
Simply scan difference in reverse order and insert delimiter in place, the loop counter i will not update with length of s.
<langsyntaxhighlight lang="lua">function splitdiff(s)
for i=#s,2,-1 do
if s:sub(i,i)~=s:sub(i-1,i-1) then
Line 1,357 ⟶ 1,865:
end
return s
end</langsyntaxhighlight>
 
=={{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}}==
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$) {
Def string m$, p$
Line 1,384 ⟶ 1,933:
}
PrintParts "gHHH5YY++///\"
</syntaxhighlight>
</lang>
 
=={{header|Maple}}==
Added an additional backlash to escape the \ character at the end.
<langsyntaxhighlight Maplelang="maple">splitChange := proc(str::string)
local start,i,len;
start := 1;
Line 1,400 ⟶ 1,949:
printf("%s", str[start..len]);
end proc;
splitChange("gHHH5YY++///\\");</langsyntaxhighlight>
{{out}}
<pre>g, HHH, 5, YY, ++, ///, \</pre>
 
=={{header|Mathematica}}/{{header|Wolfram Language}}==
 
The backslash (\) must be escaped with another backslash when defining the string.
<langsyntaxhighlight Mathematicalang="mathematica">StringJoin@@Riffle[StringCases["gHHH5YY++///\\", p : (x_) .. -> p], ", "]</langsyntaxhighlight>
 
{{out}}
<pre>g, HHH, 5, YY, ++, ///, \</pre>
</pre>
 
=={{header|MiniScript}}==
<langsyntaxhighlight MiniScriptlang="miniscript">s = "gHHH5YY++///\"
output = []
lastLetter = s[0]
Line 1,422 ⟶ 1,968:
lastLetter = letter
end for
print output.join("")</langsyntaxhighlight>
{{out}}
<pre>g, HHH, 5, YY, ++, ///, \</pre>
 
=={{header|Modula-2}}==
<langsyntaxhighlight lang="modula2">MODULE CharacterChange;
FROM Terminal IMPORT Write,WriteString,WriteLn,ReadChar;
 
Line 1,451 ⟶ 1,997:
 
ReadChar
END CharacterChange.</langsyntaxhighlight>
{{out}}
<pre>g
Line 1,462 ⟶ 2,008:
 
=={{header|Nim}}==
<syntaxhighlight lang ="nim">proc splitOnDiff(str: string) : string =
result = ""
 
if str.len < 1: return result
 
var prevChar : char = str[0]
 
for idx in 0 ..< str.len:
Line 1,481 ⟶ 2,027:
assert splitOnDiff("""gHHH5YY++///\""") == """g, HHH, 5, YY, ++, ///, \"""
 
echo splitOnDiff("""gHHH5YY++///\""")</langsyntaxhighlight>
{{output}}
<pre>g, HHH, 5, YY, ++, ///, \</pre>
 
=={{header|ooRexx}}==
<langsyntaxhighlight lang="oorexx">Parse Arg str . /*obtain optional arguments from the CL*/
If str=='' Then str= 'gHHH5YY++///\' /*Not specified? Then use the default.*/
i=1
Line 1,499 ⟶ 2,045:
i=j
End
Say ol</langsyntaxhighlight>
{{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}}
<pre>g, HHH, 5, YY, ++, ///, \</pre>
 
=={{header|Perl}}==
<langsyntaxhighlight lang="perl">use strict;
use warnings;
use feature 'say';
Line 1,518 ⟶ 2,099:
}
say "Orginal: $string\n Split: 「" . join('」, 「', @S) . "」\n";
}</langsyntaxhighlight>
{{out}}
<pre>Orginal: gHHH5YY++///\
Line 1,527 ⟶ 2,108:
 
=={{header|Phix}}==
<!--<syntaxhighlight lang="phix">-->
<lang Phix>function split_on_change(string in)
<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>
string out = ""
<span style="color: #004080;">string</span> <span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">""</span>
if length(in) then
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
integer prev = in[1]
<span style="color: #004080;">integer</span> <span style="color: #000000;">prev</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span>
for i=1 to length(in) do
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
integer ch = in[i]
<span style="color: #004080;">integer</span> <span style="color: #000000;">ch</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span>
if ch!=prev then
<span style="color: #008080;">if</span> <span style="color: #000000;">ch</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">prev</span> <span style="color: #008080;">then</span>
out &= ", "
<span style="color: #000000;">res</span> <span style="color: #0000FF;">&=</span> <span style="color: #008000;">", "</span>
prev = ch
<span style="color: #000000;">prev</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">ch</span>
end if
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
out &= ch
<span style="color: #000000;">res</span> <span style="color: #0000FF;">&=</span> <span style="color: #000000;">ch</span>
end for
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
end if
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
return out
<span style="color: #008080;">return</span> <span style="color: #000000;">res</span>
end function
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
 
puts(1,split_on_change(`gHHH5YY++///\`))</lang>
<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>
<!--</syntaxhighlight>-->
{{Out}}
<pre>
g, HHH, 5, YY, ++, ///, \
</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}}==
<langsyntaxhighlight PicoLisplang="picolisp">(de splitme (Str)
(let (Str (chop Str) Fin)
(glue
Line 1,559 ⟶ 2,167:
(conc Fin (cons X))
(link (setq Fin (cons X))) ) ) ) ) ) )
(prinl (splitme "gHHH5YY++///\\"))</langsyntaxhighlight>
{{out}}
<pre>g, HHH, 5, YY, ++, ///, \</pre>
 
=={{header|Pike}}==
<syntaxhighlight lang="pike">
<lang Pike>
string input = "gHHH5YY++///\\"; // \ needs escaping
string last_char;
Line 1,574 ⟶ 2,182:
}
 
</syntaxhighlight>
</lang>
{{Out}}
<pre>
Line 1,584 ⟶ 2,192:
 
After executing the following code, for example:
<langsyntaxhighlight lang="plainenglish">Put "abcdef" into a string.
Slap a rider on the string.</langsyntaxhighlight>
 
The rider looks like this:
<langsyntaxhighlight lang="plainenglish">Original: "abcdef"
Source: "abcdef"
Token: ""</langsyntaxhighlight>
 
Now when we <code>Bump the rider.</code>, it looks like this:
<langsyntaxhighlight lang="plainenglish">Original: "abcdef"
Source: "bcdef"
Token: "a"</langsyntaxhighlight>
 
Another bump, and:
<langsyntaxhighlight lang="plainenglish">Original: "abcdef"
Source: "cdef"
Token: "ab"</langsyntaxhighlight>
 
Now let's say we have a complete token and want to start a new one. We can
Line 1,606 ⟶ 2,214:
and now the rider looks like this:
 
<langsyntaxhighlight lang="plainenglish">Original: "abcdef"
Source: "cdef"
Token: ""</langsyntaxhighlight>
 
And that's all there is to it.
 
<langsyntaxhighlight lang="plainenglish">To run:
Start up.
Split "gHHH5YY++///\" into some string things by change of character.
Line 1,647 ⟶ 2,255:
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.</langsyntaxhighlight>
{{out}}
<pre>
Line 1,655 ⟶ 2,263:
=={{header|PowerShell}}==
{{trans|BBC BASIC}}
<syntaxhighlight lang="powershell">
<lang PowerShell>
function Split-String ([string]$String)
{
Line 1,676 ⟶ 2,284:
$splitString
}
</syntaxhighlight>
</lang>
<syntaxhighlight lang="powershell">
<lang PowerShell>
Split-String "gHHH5YY++///\"
</syntaxhighlight>
</lang>
{{Out}}
<pre>
Line 1,686 ⟶ 2,294:
 
=={{header|PureBasic}}==
<langsyntaxhighlight lang="purebasic">Procedure splitstring(s$)
Define *p.Character = @s$,
c_buf.c = *p\c
Line 1,704 ⟶ 2,312:
splitstring("gHHH5YY++///\")
Input()
EndIf</langsyntaxhighlight>
{{out}}
<pre>g, HHH, 5, YY, ++, ///, \</pre>
Line 1,712 ⟶ 2,320:
===Python3.6+===
Using [[https://docs.python.org/3.6/library/itertools.html#itertools.groupby itertools.groupby]].
<langsyntaxhighlight lang="python">from itertools import groupby
 
def splitter(text):
Line 1,719 ⟶ 2,327:
if __name__ == '__main__':
txt = 'gHHH5YY++///\\' # Note backslash is the Python escape char.
print(f'Input: {txt}\nSplit: {splitter(txt)}')</langsyntaxhighlight>
 
{{out}}
Line 1,726 ⟶ 2,334:
 
===Python: Using zip===
<langsyntaxhighlight lang="python">def splitterz(text):
return (''.join(x + ('' if x == nxt else ', ')
for x, nxt in zip(txt, txt[1:] + txt[-1])))
Line 1,732 ⟶ 2,340:
if __name__ == '__main__':
txt = 'gHHH5YY++///\\'
print(splitterz(txt))</langsyntaxhighlight>
 
{{out}}
Line 1,738 ⟶ 2,346:
 
===Python2===
<langsyntaxhighlight lang="python">import itertools
 
try: input = raw_input
Line 1,748 ⟶ 2,356:
groups.append(''.join(g))
print(' input string: %s' % s)
print(' output string: %s' % ', '.join(groups))</langsyntaxhighlight>
{{out}} &nbsp; when using the default input:
<pre>
Line 1,756 ⟶ 2,364:
 
=={{header|Quackery}}==
<langsyntaxhighlight Quackerylang="quackery">[ dup size 2 <
iff size done
behead swap
Line 1,771 ⟶ 2,379:
dip [ $ ", " join ]
recurse join ] is runs$ ( $ --> $ )
</syntaxhighlight>
</lang>
'''Testing in Quackery shell.'''
<pre>/O> $ "gHHH5YY++///\" runs$ echo$
Line 1,781 ⟶ 2,389:
=={{header|Racket}}==
{{trans|Python}}
<langsyntaxhighlight lang="racket">#lang racket
(define (split-strings-on-change s)
(map list->string (group-by values (string->list s) char=?)))
Line 1,789 ⟶ 2,397:
<
)
", "))</langsyntaxhighlight>
 
{{out}}
Line 1,798 ⟶ 2,406:
{{works with|Rakudo|2017.05}}
 
<syntaxhighlight lang="raku" perl6line>sub group-chars ($str) { $str.comb: / (.) $0* / }
 
# Testing:
Line 1,805 ⟶ 2,413:
put 'Original: ', $string;
put ' Split: ', group-chars($string).join(', ');
}</langsyntaxhighlight>
 
{{out}}
Line 1,833 ⟶ 2,441:
=={{header|REXX}}==
===version 1===
<langsyntaxhighlight 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*/
if str=='' then str= 'gHHH5YY++///\' /*Not specified? Then use the default.*/
Line 1,843 ⟶ 2,451:
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. */</langsyntaxhighlight>
{{out|output|text=&nbsp; when using the default input:}}
<pre>
Line 1,851 ⟶ 2,459:
 
===version 2===
<langsyntaxhighlight lang="rexx">/* REXX */
Parse arg str /*obtain optional arguments from the CL*/
if str=='' then str= 'gHHH5YY++///\' /*Not specified? Then use the default.*/
Line 1,870 ⟶ 2,478:
result=result||x
say ' input string: ' input
say ' output string: ' result </langsyntaxhighlight>
{{out]]
<pre> input string: gHHH5YY++///\
Line 1,876 ⟶ 2,484:
 
=={{header|Ring}}==
<langsyntaxhighlight lang="ring">
see split("gHHH5YY++///\")
 
Line 1,891 ⟶ 2,499:
next
return split
</syntaxhighlight>
</lang>
Output:
<pre>
g, HHH, 5, YY, ++, ///, \
</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}}==
<langsyntaxhighlight lang="ruby">def split(str)
puts " input string: #{str}"
s = str.chars.chunk(&:itself).map{|_,a| a.join}.join(", ")
Line 1,905 ⟶ 2,523:
end
 
split("gHHH5YY++///\\")</langsyntaxhighlight>
 
{{out}}
Line 1,914 ⟶ 2,532:
 
=={{header|Rust}}==
<langsyntaxhighlight Rustlang="rust">fn splitter(string: &str) -> String {
let chars: Vec<_> = string.chars().collect();
let mut result = Vec::new();
Line 1,947 ⟶ 2,565:
println!("input string: {}", test_string);
println!("output string: {}", splitter(test_string));
}</langsyntaxhighlight>
 
{{out}}
Line 1,958 ⟶ 2,576:
output string: g, HHH, 5, YY, ++, ///, \
</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}}==
<langsyntaxhighlight Scalalang="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
Line 1,967 ⟶ 2,608:
(s + 'X').sliding(2).map(pair => pair.head + (if (pair.head != pair.last) ", " else "")).mkString("")
 
println(runLengthSplit("""gHHH5YY++///\"""))</langsyntaxhighlight>
{{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)].
 
<syntaxhighlight lang="scala">
<lang Scala>
def runLengthSplit(s:String):List[String] = {
def recursiveSplit(acc:List[String], rest:String): List[String] = rest match {
Line 1,986 ⟶ 2,627:
val result = runLengthSplit("""gHHH5YY++///\""")
println(result.mkString(","))
</syntaxhighlight>
</lang>
{{Out}}
<pre>
Line 1,993 ⟶ 2,634:
 
=={{header|Sed}}==
<langsyntaxhighlight lang="sed">echo 'gHHH5YY++///\' | sed 's/\(.\)\1*/&, /g;s/, $//'</langsyntaxhighlight>
Output:
g, HHH, 5, YY, ++, ///, \
 
=={{header|Sidef}}==
<langsyntaxhighlight lang="ruby">func group(str) {
gather {
while (var match = (str =~ /((.)\g{-1}*)/g)) {
Line 2,006 ⟶ 2,647:
}
 
say group(ARGV[0] \\ 'gHHH5YY++///\\').join(', ')</langsyntaxhighlight>
{{out}}
<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, ++, ///, \
</pre>
 
=={{header|Standard ML}}==
<langsyntaxhighlight lang="sml">(*
* Head-Tail implementation of grouping
*)
Line 2,022 ⟶ 2,711:
fun group xs = group' nil xs
 
fun groupString str = String.concatWith ", " (map implode (group (explode str)))</langsyntaxhighlight>
 
{{out}}
Line 2,030 ⟶ 2,719:
=={{header|Swift}}==
 
<langsyntaxhighlight lang="swift">public extension String {
func splitOnChanges() -> [String] {
guard !isEmpty else {
Line 2,056 ⟶ 2,745:
}
 
print("gHHH5YY++///\\".splitOnChanges().joined(separator: ", "))</langsyntaxhighlight>
 
{{out}}
Line 2,063 ⟶ 2,752:
 
=={{header|Tailspin}}==
<langsyntaxhighlight lang="tailspin">
composer splitEquals
<reps> <nextReps>*
Line 2,071 ⟶ 2,760:
 
'gHHH5YY++///\' -> splitEquals -> !OUT::write
</syntaxhighlight>
</lang>
{{out}}
<pre>g, HHH, 5, YY, ++, ///, \</pre>
Line 2,077 ⟶ 2,766:
=={{header|tbas}}==
{{Trans|BBC BASIC}}
<langsyntaxhighlight lang="basic">SUB SPLITUNIQUE$(s$)
DIM c$, d$, split$, i%
c$ = LEFT$(s$, 1)
Line 2,093 ⟶ 2,782:
 
PRINT SPLITUNIQUE$("gHHH5YY++///\")
END</langsyntaxhighlight>
 
=={{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).
 
<langsyntaxhighlight Tcllang="tcl">set string "gHHH5YY++///\\"
 
regsub -all {(.)\1*} $string {\0, } string
regsub {, $} $string {} string
puts $string</langsyntaxhighlight>
 
{{out}}
 
<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}}==
 
<syntaxhighlight lang="vb">
<lang vb>
Option Explicit
 
Line 2,144 ⟶ 2,861:
Split_Special = R
End Function
</syntaxhighlight>
</lang>
{{out}}
<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}}==
<langsyntaxhighlight ecmascriptlang="wren">var split = Fn.new { |s|
if (s.count == 0) return ""
var res = []
Line 2,168 ⟶ 2,910:
 
var s = "gHHH5YY++///\\"
System.print(split.call(s))</langsyntaxhighlight>
 
{{out}}
Line 2,176 ⟶ 2,918:
 
=={{header|XLISP}}==
<langsyntaxhighlight lang="lisp">(defun delimit (s)
(defun delim (old-list new-list current-char)
(if (null old-list)
Line 2,187 ⟶ 2,929:
(list->string (delim (string->list s) '() (car (string->list s)))) )
 
(display (delimit "gHHH5YY++///\\")) ;; NB. The "\" character needs to be escaped</langsyntaxhighlight>
{{out}}
<pre>g, HHH, 5, YY, ++, ///, \</pre>
 
=={{header|XPL0}}==
<langsyntaxhighlight XPL0lang="xpl0">string 0; \change to zero-terminated convention
char S;
[S:= "gHHH5YY++///\";
Line 2,200 ⟶ 2,942:
S:= S+1;
];
]</langsyntaxhighlight>
 
{{out}}
<pre>
g, HHH, 5, YY, ++, ///, \
</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}}==
<syntaxhighlight lang="z80">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</syntaxhighlight>
 
{{out}}
Line 2,208 ⟶ 3,013:
 
=={{header|zkl}}==
<langsyntaxhighlight lang="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();</langsyntaxhighlight>
{{out}}
<pre>
Line 2,220 ⟶ 3,025:
 
=={{header|ZX Spectrum Basic}}==
<langsyntaxhighlight lang="basic"> 10 LET s$="gHHH5YY++///\"
20 LET c$=s$(1)
30 LET n$=c$
Line 2,228 ⟶ 3,033:
70 LET c$=s$(i)
80 NEXT i
90 PRINT n$</langsyntaxhighlight>
{{out}}
<pre>g, HHH, 5, YY, ++, ///, \</pre>
9,482

edits