g | x | w | all
Bytes Lang Time Link
141Swift200427T172431ZAlexande
188Setanta250624T230529Zbb94
073Swift 6250624T183756ZmacOSist
006Vyxal 3.7250624T113716ZThemooni
011AGL250201T052358ZErikDaPa
590Bespoke250301T212041ZJosiah W
022Uiua240306T233243Znoodle p
144CASIO BASIC CASIO fx9750GIII250204T161108Zmadeforl
014Jalapeño250204T044707ZATaco
023sed E C locale200425T042902ZMitchell
051JavaScript Node.js241227T054232Zl4m2
051GolfScript241227T041847ZErikDaPa
035Ruby pl221015T013313ZJordan
025Perl 5 p240307T032243ZXcali
004Vyxal 3 S240306T234243Zpacman25
075Scala 3240306T204100Zmovatica
016Pip230519T022043ZDLosc
005Thunno 2 Ṡ230623T170725ZThe Thon
918Nibbles230519T031158ZDLosc
057Lua230519T025324Zbluswimm
144Java 8 OpenJDK 8230402T120810ZFhuvi
005Vyxal210605T021720Zemanresu
065Zsh221110T172136Zroblogic
00805AB1E200424T232137ZExpired
076R221018T135209ZGiuseppe
006Japt v2.0a0 S200425T115315ZShaggy
106Rust221017T105000ZJSorngar
7069PHP221017T164359ZTitus
037Factor200425T084931ZGalen Iv
047K ngn/k221015T020735Zoeuf
021K ngn/k200424T221653Zngn
054AWK210302T094301Zcnamejj
024APL NARS2000 dialect210302T140742Zturnip
047PowerShell Core210302T104431Zmazzy
056PowerShell Core210302T094333Zwasif
098R210302T095814ZDominic
059Java JDK200427T081511ZOlivier
130F#200511T082941Zcloudcry
032J200505T161113ZTraws
006Jelly200425T004548ZJonathan
076Kotlin200428T071109Zsidgate
054Javascript ES6200427T214501ZQwertiy
031Raku200428T034326ZJo King
120Elixir200428T003621Zryanwinc
372TEX INITEX200427T230155ZAlban Kr
082Python 3200427T220609ZQwertiy
1592C gcc200425T142823Zsugarfi
042J200425T181257ZGalen Iv
01805AB1E200424T231106Zlyxal
080C gcc200426T053952Zdingledo
074Haskell200425T094600ZLyricLy
116C gcc200425T231843ZNoodle9
098[C#]200425T004048ZKaleSurf
006Stax200425T231917ZKhuldrae
018QuadR200425T225638ZAdá
076JavaScript ES6200425T202531ZKryštof
130Red200425T163947ZGalen Iv
032APL Dyalog Unicode200425T134243Zuser9206
110Erlang escript200425T130741Zuser9206
038Q/KDB+200425T125412Zmkst
016MATL200424T214458ZLuis Men
074C# Visual C# Interactive Compiler200425T100728Zthe defa
092Icon200425T080637ZGalen Iv
057JavaScript ES6200425T060917ZArnauld
055Python 3200424T214731ZSurculos
005Husk200425T025538Zuser9206
013Retina200424T223248ZJarmex
016Retina 0.8.2200424T231342ZNeil
026Charcoal200424T231057ZNeil
014Pyth200424T215919Zmath jun

Swift, 141 bytes

{let a=$0.unicodeScalars.filter{CharacterSet.alphanumerics.contains($0)};return zip(a,a.dropFirst()).map{"\($0)\($1)"}.joined(separator:" ")}

Ungolfed:

let ungolfed: (String) -> String = { input in
    let unicodeScalars = input.unicodeScalars.filter { char in CharacterSet.alphanumerics.contains(char) }
    return zip(unicodeScalars, unicodeScalars.dropFirst())
        .map { "\($0)\($1)" }
        .joined(separator: " ")
}

Test case runner:

import Foundation

let testCases: [(input: String, expectedOutput: String)] = [
    (input: "Ab", expectedOutput: "Ab"),
    (input: "Abc", expectedOutput: "Ab bc"),
    (input: "Abcd", expectedOutput: "Ab bc cd"),
    (input: "E?h?", expectedOutput: "Eh"),
    (input: "Blurry vision", expectedOutput: "Bl lu ur rr ry yv vi is si io on"),
    (input: "We're #1!", expectedOutput: "We er re e1"),
    (input: "I'm an example!", expectedOutput: "Im ma an ne ex xa am mp pl le"),
    (input: "This is _not_ legible", expectedOutput: "Th hi is si is sn no ot tl le eg gi ib bl le"),
    (input: "(a*b*c)+5^-x", expectedOutput: "ab bc c5 5x"),
    (input: "??a_%,1!=z#@", expectedOutput: "a1 1z"),
]

for (input, expectedOutput) in testCases {
    let actualOutput = f(input)
    assert(actualOutput == expectedOutput, """
    Wrong answer.
        input: '\(input)'
        actualOutput: '\(actualOutput)'
        expectedOutput: '\(expectedOutput)'
    
    """)
}
```

Setanta, 188 bytes

gniomh(s){t:=""le i idir(0,fad@s)le j idir(0,62)ma"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"[j]==s[i] t+=s[i]s=""le i idir(1,fad@t)s+=" "*(i-1&1)+t[i-1]+t[i]toradh s}

try-setanta.ie link

Swift 6, 73 bytes

{($0+"").replacing(/\W|_/,with:"").replacing(/(?!^|.$)./){$0.0+" "+$0.0}}

Try it on SwiftFiddle!

Vyxal 3.7, 6 bytes

~ɾv¨“„

Vyxal It Online!

~ɾv¨“„­⁡​‎‎⁡⁠⁡‏⁠‎⁡⁠⁢‏‏​⁡⁠⁡‌⁢​‎‎⁡⁠⁣‏‏​⁡⁠⁡‌⁣​‎‎⁡⁠⁤‏⁠‎⁡⁠⁢⁡‏‏​⁡⁠⁡‌⁤​‎‎⁡⁠⁢⁢‏‏​⁡⁠⁡‌­
~ɾ      # ‎⁡filter implicit input by is-alphabetical
  v     # ‎⁢overlapping pairs
   ¨“   # ‎⁣join each pair on empty string
     „  # ‎⁤join on spaces
💎

Created with the help of Luminespire.

<script type="vyxal3">
~ɾv¨“„
</script>
<script>
    args=[["This is _not_ legible"],["Blurry vision"],["I'm an example!"]]
</script>
<script src="https://themoonisacheese.github.io/snippeterpreter/snippet.js" type="module"/>

AGL, 11 bytes

‘0s@-2/' $$

Explanation:

‘0s@-2/' $$
‘0s@-       => keep all alphanumeric characters in the input
     2/     => subarrays of length 2
       ' $$ => ' '.join()

Bespoke, 590 bytes

getting somewhat b-l-urry for my sight
anything in your eye is but pictures
so spotting something written out,written rightly:never is it seen
for my words reappear,and my eyes deceive
visions blur-r-y;this is my sight
and it reappears;a lot of things will
visions blur-r-y;cant fix my sight
and now a so-bad eye is imagining things
visions blur-r-y;weakened eyes,weakened eyes
wouldnt it be nice,viewing any ordinary written letters
and so repeated ones-s-s-s surface nowhere
look now at chart:an E appears on top of one
if letter is smaller,and cannot be so seen,we plop lenses on my eyes

This is the first time I've used a function in a golfed Bespoke program! It's defined at the very top of the program, and it's called with visions blur-r-y.

The helper function takes three numbers n, b, and a, and it returns 1 if a < n < b and 0 otherwise; this is to check whether each input codepoint is within the right range for numbers, uppercase letters, or lowercase letters.

Uiua, 22 bytes

/$"_ _"⧈⊟▽↥⌵±⤙⊸∊+@0⇡10

Try it: Uiua pad

CASIO BASIC (CASIO fx-9750GIII), 144 bytes

?→Str 9
For 1→N To StrLen(Str 9
StrMid(Str 9,N,1→Str 8
StrSrc("ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890",Str 8)⟹Str 1+Str 8→Str 1
Next
For 1→N To StrLen(Str 1)-1
3N-2
Locate Ans Rmdr 21,3+Ans Int÷ 21,StrMid(Str 1,N,2)
Next

it works, lol.

Jalapeño, 14 bytes

∩{₃A∪a∪{₂0‥9↩‥}w₋

Explained

∩{₃A∪a∪{₂0‥9↩‥}w₋
∩                 # Intersect: All elements of the input that are also in:
 {₃A∪a∪{₂0‥9      # All alphanumeric characters. Uppercase alphabet union lowercase alphabet union numbers 0 - 9.
            ↩‥}   # Fold via concatenation, combining pairs of letters.
               w₋ # Deword: Join by spaces

Hex-Dump of Bytecode

       0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
0000: ef c7 26 ee 27 ee c6 30 2e 39 d4 2e c5 16       

Try it Online!

All test cases

sed -E (C locale), 46 33 23 bytes

s/\W|_//g;s/\B.\B/& &/g

Try it online!

Thanks to pizzapants184 for a 13-byte improvement.

10 more bytes off thanks to Dom Hastings.


Input on stdin, and output on stdout.

If your locale isn't set to C, you can set it with: export LC_ALL=C

JavaScript (Node.js), 51 bytes

s=>(s+0).replace(/(_|\W)*(.)/g,'$2 $2').slice(2,-5)

Try it online!

GolfScript, 51 bytes

[{0,+''+10,{48+}%26,{.65+\97+}%+''+&}%.-1<\1>]zip' '*

Explanation:

[{0,+''+10,{48+}%26,{.65+\97+}%+''+&}%.-1<\1>]zip' '*
        10,{48+}%26,{.65+\97+}%+''+                   => alphanumeric characters
 {0,+''+                           &}%                => keep all alphanumeric characters
[                                     .-1<\1>]zip     => list of adjacent characters
                                                 ' '* => ' '.join()

Ruby -pl, 48 39 35 bytes

Similar to my own original solution, this is now basically a port of Xcali's Perl 5 solution; give them an upvote.

gsub /\W|_/,""
gsub /\B.\B/,'\& \&'

Attempt This Online!

Perl 5 -p, 25 bytes

s/\W|_//g;s/\B.\B/$& $&/g

Try it online!

Vyxal 3 S, 4 bytes

/““o

Try it Online!

janky formatting allows for a 3 byter

Scala 3, 75 bytes

_.map(c=>if(c.isLetterOrDigit)c+" "+c else"").mkString.drop(2).dropRight(2)

Attempt This Online!

Pip, 17 16 bytes

_.BMP(aXA,XD)J:s

Attempt This Online!

Explanation

_.BMP(aXA,XD)J:s
       XA         ; Regex matching any letter character
          XD      ; Regex matching any digit
         ,        ; Combine them using alternation (match one OR the other)
     (a     )     ; Find all matches in command-line argument
   MP             ; Map this function to each pair of adjacent results:
_                 ;  The first
 .                ;  concatenated with
  B               ;  the second
             J:s  ; Join the resulting list on spaces

Using the -s flag would remove the need for the final three bytes.

Thunno 2 , 5 bytes

œȦDḣZ

Attempt This Online!

Explanation

œȦDḣZ  # Implicit input
œ      # Filter the input by:
 Ȧ     #  Is alphanumeric?
  D    # Duplicate
   ḣ   # Remove the first item
    Z  # Zip them together
       # Join by spaces
       # Implicit output

Nibbles, 9 bytes (18 nibbles)

*" "`'`:<<;|@\$n>>$

Attempt This Online!

Explanation

*" "`'`:<<;|@\$n>>$
            @        Line of stdin
           |         Filter its characters on this function:
             \$n      Character is alphanumeric
          ;          Store the result as $
        <<           Remove last character
                >>$  Take another copy of $ and remove first character
      `:             Put both strings in a list
    `'               Transpose, giving a list of 2-character strings
*" "                 Join on spaces

Lua, 57 bytes

io.write((...):gsub('%W',''):gsub('.','%1 %1'):sub(3,-3))

Try it online!

Performs three steps:

Java 8 (OpenJDK 8), 144 bytes

No regexp, using only a single inline Stream

s->s.chars().filter(e->e>47&e<58|e>64&e<91|e>96&e<123).mapToObj(e->""+(char)e).reduce("",(a,b)->a+(a.length()<2?b:" "+a.charAt(a.length()-1)+b))

Try it online!

Vyxal, 5 bytes

kr↔zṄ

Try it Online!

kr↔   # Remove non-alphanumeric
   z  # Get chunks of length 2
    Ṅ # Join with spaces

Zsh, 65 bytes

b=(${(s::)@//[^0-9A-Za-z]});for i ({2..$#b})printf $b[i-1]$b[i]\ 

try it online!

There is a a space character after the backslash: \

05AB1E, 8 7 8 bytes

-1 byte thanks to @CommandMaster

+1 byte again thanks to @KevinCruijssen finding an issue

žKÃüJðý?

Try it online!

R, 76 bytes

function(s)cat(substring(S<-gsub("[^a-z0-9]","",s,T),N<-1:(nchar(S)-1),N+1))

Try it online!

Similar to Dominic van Essen's answer, uses cat to join by spaces; uses substring which recycles (as opposed to substr which doesn't).

Japt v2.0a0 -S, 6 bytes

r\W ä+

Try it

r\W ä+     :Implicit input of string
r          :Replace
 \W        :  Regex /[^a-z0-9]/gi
    ä+     :Consecutive pairs reduced by concatenation
           :Implicit output, joined with spaces

Rust, 144 129 127 126 123 120 106 bytes

-3 bytes, thanks @mousetail
-14 bytes, thanks @corvus_192

Playing with strings can be subtle, and as such it is easy to slam face first into the borrow checker when trying to golf string manipulation in rust. As a result I welcome any improvement to this code:

|s|{let a:String=s.filter(|c|c.is_alphanumeric()).flat_map(|c|[c,' ',c]).collect();a[2..a.len()-2].into()}

The solution is the same as for the Python one above.

Ungolfed:

// This first line is not part of the code snippet,
// but needs to be present in the driving code in order for type inference to work.
let blur: fn(std::vec::IntoIter<char>) -> String = 
    |s| {                                    // Take in an iterator over
                                             // a vector of chars and
        let a: String = s                    // build a new string
            .filter(|c| c.is_alphanumeric()) // by taking all alphanumeric characters
            .flat_map(|c| [c, ' ', c])       // and replacing them with a copy
                                             // of themselves around a space
            .collect();                      // and collecting them into a String.
        a[2..a.len() - 2].into()             // Then make a string slice of every 
                                             // character except the first and last
                                             // two and convert that slice
                                             // into a String.
                                             // `.into()` works because of the
                                             // function signature that is specified
                                             // on the first line.
};

println!(
    "{}",
    // We call this closure by passing it an iterator over a vector of characters
    // that we build by iterating over the characters in a string.
    blur("This is a string"    
        .chars()
        .collect::<Vec<_>>()
        .into_iter())
);

Attempt this online

PHP, 70 bytes / 69 bytes

while(~$c=($s=preg_replace('/\W/','',$argn))[++$i])echo$s[$i-1],"$c ";

run these 70 bytes as pipe with -nr, ignore the warnings

or run this port of Qwertiy´s JavaScript solution (69 bytes) as pipe with -nR:

<?=preg_replace('/.(?=(.).)/','$0$1 ',preg_replace('/\W/','',$argn));

Try them online

Factor, 51 37 bytes

-14 bytes thanks to chunes

[ [ alpha? ] filter 2 clump " "join ]

Try it online!

Factor, 51 bytes

: b ( s -- s ) [ alpha? ] filter 2 clump " " join ;

Try it online!

Unbelievably Factor is competitive with Python and JavaScript :)

K (ngn/k), 47 bytes

{" "/2':x^"!@#$%^&*()~`_-+={}[]|\:;\"'<>?,./ "}

Try it online!

The window adverb finally got a use for once. Also, removing non-alphanumeric is such a huge pain to write.

Anyways, here's the explanation:

{" "/2':x^"!@#$%^&*()~`_-+={}[]|\:;\"'<>?,./ "}  Main function. Takes x as input
          "!@#$%^&*()~`_-+={}[]|\:;\"'<>?,./ "   Hard-coded non-alphanumeric string
        x^                                       Remove all of them in x
     2':                                         Window (Get chunks of x at length 2)
 " "/                                            Join the chunks with whitespace

K (ngn/k), 27 24 22 21 bytes

" "/2':(2!"/9@Z`z"')_

Try it online!

"/9@Z`z"' binary search in the given string

2! mod 2

(2!"/9@Z`z"')_ drop non-alphanumeric chars

2': make a list of pairs of adjacent chars

" "/ join with spaces

AWK, 52 54 bytes

{gsub("\\W|_",a);for(b=$0;c=substr(b,++d,2);)$d=c}--NF

Try it online!

Fixed underscore rule goof (+2 chars), thanks to Pedro Maimere

Here's what's going on with this one...

gsub("\\W",a)

Removes all the non-alphabetic characters from the input string since $0 is the default target for gsub. Using an unitialized variable a instead of "" saves a byte.

Next the code loops through the string taking 2 character slices and assigns them to positional variables.

for(b=$0;

The setup has to save $0 to another variable, since changing the positional variables impacts the collected input in $0 as well.

c=substr(b,++d,2);

The "test" at the top of the loop does a couple of things in one statement:

The body of the loop sets the next positional variable to the slice we just took.

$d=c

After all the positional variables have been set, there's one "garbage" entry on the end with one character. So the test:

--NF

effectively drops that last positional variable and triggers the default action, which prints all the positional variables separated by a space.

APL (NARS2000 dialect) 24 bytes

{¯1↓1↓⍕2,/⍵/⍨⍵∊A←⎕a,⎕A,⎕D}

PowerShell Core, 48 47 bytes

''+($args-match'[a-z\d]'|%{,"$p$_"*!!$p;$p=$_})

Try it online!

PowerShell Core, 56 bytes

$n=$args|% t*y|%{$_+" "+$_}
-join$n[0..($n.length-2)+-1]

Try it online!

-20 bytes for @mazzy

R, 98 bytes

function(x,y=grep("[a-z0-9]",el(strsplit(x,"")),T,,T))for(i in seq(y)[-1])cat(y[i-1:0],' ',sep='')

Try it online!

Unusually for R, a for loop is significantly shorter than a matrix-based approach, mainly because it allows us to just use cat instead of the much-more-verbose Reduce(paste vectorized way to build a text string from a list of characters.

Java (JDK), 59 bytes

s->s.replaceAll("\\W|_","").replaceAll(".(?=(.).)","$0$1 ")

Try it online!

F#, 130 bytes

let f s=s|>Seq.filter Char.IsLetterOrDigit|>fun x->Seq.tail x|>Seq.zip x|>Seq.map(fun(a,b)->string a+string b)|>String.concat" "

J, 32 bytes

[:}:[:,/2,&' '\]-.-.&AlphaNum_j_

Try it online!

               -.-.&AlphaNum_j_   remove non-alphanumeric
       2,&' '\                    append space to each pair of adjacent chars 
     ,/                           join 
 }:                               remove trailing space

Jelly, 6 bytes

fØB;ƝK

A monadic Link accepting a list of characters which yields a list of characters.

Try it online!

How?

fØB;ƝK - Link: list of characters, S
 ØB    - base-62 characters = "01...89AB...YZab...yz"
f      - (S) filter keep if in (that)
    Ɲ  - for neighbours:
   ;   -   concatenate
     K - join with spaces

Kotlin, 77 76 bytes

{it.filter{it.isLetterOrDigit()}.zipWithNext{a,b->"$a$b"}.joinToString(" ")}

Old solution

{it.replace("\\W|_".toRegex(),"").zipWithNext{a,b->"$a$b"}.joinToString(" ")}

Javascript ES6, 55 54 chars

s=>s.replace(/\W|_/g,"").replace(/.(?=(.).)/g,"$&$1 ")

Test:

f=s=>s.replace(/\W|_/g,"").replace(/.(?=(.).)/g,"$&$1 ")

console.log(`Ab -> Ab
Abc -> Ab bc
Abcd -> Ab bc cd
E?h? -> Eh
Blurry vision -> Bl lu ur rr ry yv vi is si io on
We're #1! -> We er re e1
I'm an example! -> Im ma an ne ex xa am mp pl le
This is _not_ legible -> Th hi is si is sn no ot tl le eg gi ib bl le
(a*b*c)+5^-x -> ab bc c5 5x
??a_%,1!=z#@ -> a1 1z`.split`
`.map(s=>s.split` -> `).map(([s,k])=>f(s)==k).every(x=>x))

Raku, 31 bytes

{@$_ Z~.skip}o{S:g/\W|_//.comb}

Try it online!

The extra requirement for stripping non-alphanumeric characters takes up more than half of the bytes.

Elixir, 120 bytes

b=fn w->import String;l=replace(w,~r/[\W_]/,"");for(i<-0..String.length(l)-2,do: at(l,i)<>at(l,i+1))|>Enum.join(" ") end

Try it online!

TEX (INITEX), 372 bytes

\catcode`~13\let~\catcode~`{1~`}2~`#6~`\ 12~`|13\let|\expandafter\def\z{}\def\f#1{#1}\def\i#1{}\def\b#1#2{\ifx#2\e|||\i|\i\else|\f\fi{\ifcat#1a|\f\else|||\b|||#2|\i\fi}{\ifcat#2a #1#2|\b|#2\else|\b|#1\fi}}\def\t{~`011~`111~`211~`311~`411~`511~`611~`711~`811~`911~`\|12~`\~12~`\#12~`\{12~`\}12~127=12~`\%12~`\\12\read16to\x\edef\r{|\b\x\e}\immediate\write16{|\i\r\z}\end}\t

For example, the program being saved in a file named "codegolf.tex", provided with input ??a_%,1!=\z#@, initex codegolf.tex outputs:

This is TeX, Version 3.14159265 (TeX Live 2019/dev/Debian) (INITEX)
(./codegolf.tex
\x=??a_%,1!=\z#@
a1 1z
 )
No pages of output.
Transcript written on codegolf.log.

In the case of a degraded input, for example the strings ??, ?a, or a?, this implementation does not print any pair.

Explanation

Basis for a TEX program

\read16

Per this Meta answer, the input of a program written in TEX should come from standard input, which is the in register number 16.

\immediate\write16

The TEX Codegolf community prefers to output to DVI or PDF, because it is simpler than writing to the terminal. However, this requires a valid \output routine, which either requires a format (with more category codes to alter1) or is longer to define. So I write to the terminal. (\message could also have been used, but I don't like how the output is surrounded by TEX chat on the same line).

Because I output to the terminal, I also feel that no DVI file should get produced, so \immediate is required2.

\end

This is a complete program, so it must end with \end to run cleanly.

Category codes

Running on alphanumerics and ignoring punctuation is a trivial matter for TEX. All I have to do is to customize the category codes of those characters.

For this subject, I will use category code 11 ("letter") for characters that need to be blurred, and category code 12 ("other") for characters that are to be dropped. That choice comes from the defaults of (ini)TEX, where letters are already set to 11 and most of the other characters to 12.

\catcode`~13\let~\catcode

To save bytes, I make ~ an active character and set its meaning to \catcode. In the rest of the explanation, that alias will be ungolfed.

\catcode`{=1 \catcode`}=2 \catcode`#=6 \catcode`\ =12

These are required for INITEX to interpret my program correctly: { is now the begin-group character, } the end-group, # the macro argument, and is considered a normal character (so that the first spurious space of output can be removed). These choices are widely used in the TEX world and do not cost bytes3.

\catcode`|=13 \let|=\expandafter

This is an useful alias for later.

\def\t{\catcode`0=11 ... \end}
\t

This is a TEX design pattern that fools TEX's eyes. Everything that is written in the \todo macro definition will get a category code assigned, and this category code will not be reconsidered when TeX expands the macro. Most notably:

\catcode`\\=12

This makes the escape character \ a normal character when read from the user input.

\read16to\x \edef\r{|\b\x\e} \immediate\write16{|\i\r\z} \end

When reading the macro definition, TEX has decided that these were control words, and TEX will not reconsider this choice after the macro has been expanded, even if \ has lost its special meaning in the meantime.

\catcode127=12

The DEL character is contained in ASCII, so it should be valid input per the subject's rules. But in order to change its category code to 12, the DEL character has to be written, and the most efficient4 way to input it in TEX is to name it by its code point.

\catcode`0=11 ... \catcode`\\=12

Here are three groups of category code assignments: make the digits like letters, revert the changes made at the beginning of the program, and cancel other INITEX defaults (DEL, %, \, but not the new line because the subject emits the hypothesis:)

Your input will be a single-line string

The blurring command

Because I opted for terminal output, and because \write does not executes its argument (only expands it), I am forced to write the \blur macro as fully expandable.

\def\z{} \def\firstofone#1{#1} \def\ignore#1{}

As a prolog, I define three macros, which are commonly used in various fully-expandable design patterns. The first one is the empty macro, the second one is the identity macro, and the third one is the zero macro.

\def\blur#1#2{ ... }

The \blur macro is recursive5. It takes two characters at a time (because the rules say that the input is longer than two). Its definition is made of three parts.

\ifx#2\e \expandafter\expandafter \expandafter\ignore \expandafter\ignore
\else    \expandafter\firstofone
\fi

is the recursion condition: if the end-of-string marker (the undefined command \e6) is found, ignore the two other parts. (More precisely, drop the unused portion of the conditional \else...\fi at \expandafter level 0, then ignore the second part at \expandafter level 1, then ignore the third part at \expandafter level 2.) Otherwise, close the conditional and interpret the second part.

\ifcat#1a \expandafter\firstofone
\else \expandafter\expandafter \expandafter\blur
      \expandafter\expandafter \expandafter#2
      \expandafter             \ignore
\fi

handles the first character. If it is a letter or digit, go analysing a second character. Otherwise, skip the remaining of the conditional, ignore the third part, and call \blur recursively with #1 being dropped and #2 as the first character7 (an other one will get extracted from input).

\ifcat#2a ␣#1#2 \expandafter\blur \expandafter#2
\else \expandafter\blur \expandafter#1
\fi

handles the second character. If it is a letter or digit, output a space then the first part of the blur, then forget about #1 and call \blur recursively on #27. Otherwise, forget about it and call \blur recursively on #17.

Calling the blurring command on real input

\read16 to \x

will store the input into an (expandable) macro \x.

\expandafter\blur \x \e

This is how the \blur macro is called. Because \blur acts on tokens, the input contained in \x must be expanded first. The end-of-string marker follows.

\edef\result{\expandafter\blur \x \e}

The result of the expansion, including the whitespace at front, is stored into the \result macro.

\expandafter\ignore \result \z

Inside the \write16 command, the \result macro is first expanded. Then, \ignore eliminates the first token of output: the first space if the output is non-empty, or the \z macro call if the output is empty. In the first case, the \z macro will survive; but \write16 will finally expand it, and its expansion is a no-op. This is the most efficient way of handling the “no trailing space” requirement, even if it requires 24 bytes (the definition and call of \z and \return); suppressing a space at the end of the output would have been nearly impossible.

☡ Footnotes

  1. $, &, ^, _, NUL, SPC, TAB, ~ for plain TEX; 5 bytes each = 40 bytes.

  2. Without \immediate, \write adds its content to a whatsit box, thus generating a page of output.

  3. Because there are only three category code changes, it is not worth putting them in a group to save the reverting.

  4. Decimal: 127= (4); Hexadecimal: "7F= (4, harder to read); Octal: '199= (5); Escape sequence: ``\^^? (5, plus \catcode`^7 and revert)

  5. It is even tail-recursive, which in TEX has the meaning of "it does not add tokens after the recursive call", and by doing so is more memory-friendly.

  6. Because all input other than my program does not get interpreted, the \e command cannot be defined later.

  7. This would fail if #2 was a simple group of arguments, but fortunately the input cannot contain simple groups, because no character has category code 1 nor 2.

Python 3, 82 chars

a=[c for c in input() if c.isalnum()]
print(' '.join(a+b for a,b in zip(a,a[1:])))

Try it: https://ideone.com/dxJU8e

C (gcc), 159 bytes (-2 more bytes thanks to S.S. Anne and JustinCB)

main(a,b)char**b;{b++;for(a=0;a<strlen(*b);a++){if(isalnum((*b)[a])){a?putchar((*b)[a]):0;a&&a<strlen(*b)-1?putchar(32):0;a<strlen(*b)-1?putchar((*b)[a]):0;}}}

Try it online!

J, 42 bytes

1}.[:,/2' '&,\]#~'/9@Z`z'(2|I."#.)&(3&u:)]

Try it online!

Inspired by ngn's ngn/k solution

Explanation

                                   (3&u:)     convert to integer both
                                         ]    the input
                 '/9@Z`z'                     and the symbols surrounding the digits, 
                                              uppercas and lowercase letters
                         (2|I."#.)&           and find in which interval lies each char
                                              then check if it's an odd one
              ]#~                             use the above to filter the input
       2' '&,\                                prepend each pair of adjacent chars
                                              with a space
   [:,/                                       flatten the result 
1}.                                           and drop the leading space 

05AB1E, 23 19 18 bytes

žKég<F®Nè?®N>è?ð?

Try it online!

This probably could be really shorter, but I just wasn't able to find the right tools for the job. -4 bytes thanks to petStorm and a further byte thanks to Command Master.

Old Answer Explained

žj'_ммм©g<F®Nè?®N>è?' ?
žj                      # Push [a-zA-Z0-9_]
  '_м                   # Remove the "_" from the above string
     м                  # Remove all alphanum characters from the input, leaving non-alphanum chars
      м                 # Remove those non-alphanum chars from the input, leaving alphanum chars
       ©                # Put this string into the register
        g<F             # For N in range(0, len(input) - 1):
           ®Nè?         #   Index the string at position N and print
               ®N>è?    #   Index the string at position N + 1 and print
                    ' ? #   Print a space

C (gcc), 80 bytes

p,b;f(char*s){for(p=b=0;*s;s++)isalnum(*s)?p&&printf(" %c%c"+!b--,p,*s),p=*s:0;}

Try it online!

Haskell, 86 74 bytes

-12 bytes thanks to Khuldraeseth na'Barya

import Data.Char
unwords.map(\(x,y)->[x,y]).(zip<*>tail).filter isAlphaNum

Try it online!

C (gcc), 123 \$\cdots\$ 117 116 bytes

i;f(char*s){char*t=s;for(i=0;t[i+=!!isalnum(*s++)]=*s;);for(putchar(*t++);t[1];)printf("%c %1$c",*t++);putchar(*t);}

Try it online!

[C#], 163 155 133 128 127 128 114 112 133 98 bytes

i=>{var b=i.Where(char.IsLetterOrDigit);return b.Select((n,i)=>i==0|i==b.Count()-1?n+"":n+" "+n);}

Run it

Have not used a Regex yet in a Codegolf, so very excite. Regex uses way too many characters. No longer excite.

Stax, 6 bytes

£Q·H°·

Run and debug it at staxlang.xyz!

Unpacked (7 bytes) and explanation:

VL|&2BJ
VL         Push string of all alphanumeric characters.
  |&       Remove from the input all letters not in this string.
    2B     All length-2 substrings
      J    Join with spaces

QuadR, 18 bytes

1↓∊' ',¨2,/⍵
\W|_

Try it online!

Replaces all non-word characters and underscores (\W|_) with nothing , and then:

2,/⍵ adjacent pairs

' ',¨ prepend a space to each pair

ϵnlist (flatten)

1↓ drop the first space

JavaScript (ES6), 54 76 bytes

a=>[...a.replace(/[\W_-]/g,'')].map((a,b,c)=>a+c[b+1]).slice(0,-1).join(' ')

Try it online!

Red, 130 bytes

func[s][a: charset[#"0"-#"9"#"A"-#"Z"#"a"-#"z"]parse s[any[p: change
a(rejoin[p/1" "p/1])| remove skip]]take/part/last s 2 at s 3]

Try it online!

APL (Dyalog Unicode), 32 bytes (SBCS)

Port of Surculose Sputum's Python answer.

{¯2↓2↓⊃,/{⍵' '⍵}¨⍵∩⎕A,819⌶⎕A,⎕D}

Try it online!

Erlang (escript), 110 bytes

Port of the Python answer.

f(X)->R=lists:flatten([[I]++" "++[I]||I<-X,re:run([I],"[A-Za-z0-9]")/=nomatch]),string:slice(R,2,length(R)-4).

Try it online!

Q/KDB+, 38 bytes

Solution:

{" "sv -2_2#'next\[x inter .Q.an _52]}

Examples:

q){" "sv -2_2#'next\[x inter .Q.an _52]}"Ab"
"Ab"
q){" "sv -2_2#'next\[x inter .Q.an _52]}"Abc"
"Ab bc"
q){" "sv -2_2#'next\[x inter .Q.an _52]}"E?h?"
"Eh"
q){" "sv -2_2#'next\[x inter .Q.an _52]}"This is _not_ legible"
"Th hi is si is sn no ot tl le eg gi ib bl le"

Explanation:

{" "sv -2_2#'next\[x inter .Q.an _52]} / solution
{                                    } / lambda taking implicit x
                           .Q.an       / "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789"
                                 _52   / drop element at index 52
                   x inter             / intersection of x and alphanumerics
             next\[                 ]  / scan along input
          2#'                          / take first 2 characters of each
       -2_                             / drop final two items
 " "sv                                 / join (sv) with " "

MATL, 17 16 bytes

t8Y2m)2YC!Z{0&Zc

Try it online! Or verify all test cases.

Explanation

Consider input 'Blurry vision'.

t      % Implicit input. Duplicate
       % STACK: 'Blurry vision', 'Blurry vision'
8Y2    % Push '012...9ABC...Zabc...z' (predefined literal)
       % STACK: 'Blurry vision', 'Blurry vision', '012...9ABC...Zabc...z'
m      % Ismember: true for chars of the first string that are in the second
       % STACK: 'Blurry vision', [1 1 1 1 1 1 0 1 1 1 1 1 1]
)      % Use as logical index. This keeps only letters and numbers in the input
       % STACK: 'Blurryvision'
2YC    % Character matrix with sliding blocks of length 2 as columns
       % STACK: ['Blurryvisio';
                 'lurryvision']
!      % Transpose
       % STACK: ['Bl';
                 'lu';
                 ...
                 'on']
Z{     % Cell array of matrix rows
       % STACK: {'Bl' 'lu ... 'on'}
0&Zc   % Join with character 0 (which will be displayed as space)
       % STACK: 'Bl lu ur rr ry yv vi is si io on'
       % Implicit display

C# (Visual C# Interactive Compiler), 74 bytes

This ended up very similar to the Python answer. I was trying something noticeably more interesting with Aggregate, but the terrible no trailing whitespace requirement made it too long.

s=>s.SelectMany(c=>char.IsLetterOrDigit(c)?c+" "+c:"").Skip(2).SkipLast(2)

Try it online!

Icon, 92 bytes

procedure f(s)
t:=""
find(k:=!s,&letters++&digits--'_')&t||:=k||' '||k&\z
return t[3:-2]
end

Try it online!

JavaScript (ES6), 57 bytes

s=>s.replace(/\W|_|(.)/g,(_,c)=>c?c+' '+c:'').slice(2,-2)

Try it online!

Python 3, 57 55 bytes

lambda s:"".join((c+" "+c)*c.isalnum()for c in s)[2:-2]

Try it online!

How:

Husk, 5 bytes

wX2f□

Try it online!

Explanation

   f   Keep all items that
    □  Is an alphanumeric character.
 X     Pick all sublists
  2    With a length of 2.
w      Join the output list by spaces.

Retina, 13 bytes

\W|_

Lw| `..

Try it online!

Explanation

\W|_ Replace each character NOT in the regex group \W (which is A-Z,a-z,0-9,_) or a _ with nothing

Lw| `.. Compute lists (L) for each set of two characters (..) starting at all positions in the string (w) and separate the lists with a space (| )

Retina 0.8.2, 17 16 bytes

\W|_

M&!`..
¶
 

Try it online! Link includes test cases. Explanation: Now basically a port of @Jarmex's Retina 1 solution, except that M! always joins with newlines, so I have explicitly change them to spaces. Previous 17-byte approach:

\W|_

\B.\B
$& $&

Try it online! Link includes test cases. Explanation:

\W|_

Delete any non-word character and any underscore (which is the only non-alphanumeric character that counts as a word character).

\B.\B
$& $&

Duplicate each inner character and space separate the results.

Charcoal, 26 bytes

≔ΦS№⁺α⁺β⭆χλιθ⪫E⊖Lθ✂θι⁺²ι¹ 

Try it online! Link is to verbose version of code. Explanation:

≔ΦS№⁺α⁺β⭆χλιθ

Filter out any character that can't be found in the upper or lower case alphabet and isn't a digit.

⪫E⊖Lθ✂θι⁺²ι¹ 

Extract all substrings of length 2 and join them together on spaces.

Pyth, 14 bytes

jd.::Q"\W|_"k2

Try it online!