# Bl lu ur rr ry yv vi is si io on - Blur the text

Given a string as input, generate a "blurred" version of that string.

# Input

Your input will be a single-line string of ASCII characters, containing a minimum of 2 alphanumeric characters

# Output

A string that is the "blurred" version of the input string.

A blurred string is one where every alphanumeric character from the original string has been paired with the ones adjacent to it, and each pair is separated by a space.

Any non-alphanumeric characters (whitespace, puncuation) in the input string must be ignored when determining adjacency of alphanumeric characters, and they must not included in the blurred string.

There must be no leading or trailing whitespace in the output string.

# Examples

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

This is code-golf, so fewest bytes wins!

• The non-alphanumeric characters have to be ignored or can be ignored?
– RGS
Apr 24 '20 at 21:39
• @RGS Thanks for the clarification question, non-alphanumeric characters must be ignored Apr 24 '20 at 21:42
• I feel like this challenge suffers from a lot of poorly motivated add-ons. For example removing certain characters from the string, or requiring no trailing whitespace. These additions don't really have a reason to exist or an internal logic, they just get in the way of writing an answer. I started to write an answer but found these extra conditions inflated my code by nearly three times, making them actually the bulk of the challenge. Apr 24 '20 at 23:18
• Here are some posts 1 2 where you can read more about why I disagree with these extraneous elements. Apr 24 '20 at 23:21
• Why no trailing whitespace? Why do we have to ignore non-alphanumeric characters? These just seem like a lot of extra requirements that make the challenge less fun. Apr 25 '20 at 20:15

# J, 42 bytes

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


Try it online!

Inspired by ngn's ngn/k solution

## Explanation

                                   (3&u:)     convert to integer both
]    the input
'/9@Zz'                     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


# 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!

• You can save some bytes: i;main(a,b)char**b;{b++;for(i=0;i<strlen(*b);i++){if(isalnum((*b)[i]))putchar(i?(*b)[i]:0);putchar(i&&i<strlen(*b)-1?32:0);putchar(i<strlen(*b)-1?(*b)[i]:0);}} Apr 25 '20 at 15:17
• The above version moves the declaration of i outside of main, allowing it to be implicitly declared as an int(saving 4 bytes) & moves the declaration of b's type after the function declaration, K&R-style, which allows a to be implicitly declared as an int(saving 2 bytes) Apr 25 '20 at 15:19
• Actually, for your code to work properly for the more advanced test cases, you need to wrap the putchar's in brackets, adding 2 bytes: i;main(a,b)char**b;{b++;for(i=0;i<strlen(*b);i++){if(isalnum((*b)[i])){putchar(i?(*b)[i]:0);putchar(i&&i<strlen(*b)-1?32:0);putchar(i<strlen(*b)-1?(*b)[i]:0);}}} Apr 25 '20 at 15:24
• Cool, thanks! I'll update the answer. Apr 25 '20 at 15:36
• I don't think outputting null bytes is allowed. Also, you can remove i; and use a instead. Apr 25 '20 at 20:06

# 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!

{@$_ 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. # 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  # 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" "  # 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: • increments d, the "current character" pointer • sets variable c to the next 2 character slices of the input • the true/false test simple has the code looping until we run off the string and get a null 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.

• Great explanation, again. Mar 2 at 10:20
• Nice piece of code! According to the question's examples, underscores (_) are meant to be erased. Unfortunately, gawk's \W is the same as [^[:alnum:]_], so the underscores are not erased. Thus, the regex would become "\\W|_". Jun 5 at 0:54
• Nice catch! I'll update the code to add the underscore. Jun 5 at 1:05

# 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!

# 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, """
input: '\(input)'
actualOutput: '\(actualOutput)'
expectedOutput: '\(expectedOutput)'

""")
}
$$$$


# 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

# Java (JDK), 59 bytes

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


Try it online!

# VyxalS, 2615 7 bytes

kr↔2lvṅ


Try it Online!
-6 thanks to @astonearachnid
-5 from some of my tricks.
-8 thanks to lyxal.

• 20 bytes: Try it Online! Jun 5 at 13:30
• @astonearachnid Thanks! Building on that, I got to 15 bytes. Jun 6 at 1:39
• Try it Online! for 10 Jun 6 at 3:58
• Try it Online! for 7 Jun 6 at 3:59

# 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.

# PowerShell Core, 56 bytes

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


Try it online!

-20 bytes for @mazzy

• nice. you don't need $s. see Try it online! Mar 2 at 10:06 • @mazzy thanks for it! Mar 2 at 10:07 • Wasif, I think improvements are needed here. See test case Blurry vision Mar 2 at 10:11 # PowerShell Core, 48 47 bytes ''+($args-match'[a-z\d]'|%{,"$p$_"*!!$p;$p=\$_})


Try it online!

# APL (NARS2000 dialect) 24 bytes

{¯1↓1↓⍕2,/⍵/⍨⍵∊A←⎕a,⎕A,⎕D}
`
• Thank you for format editing, @ppery Mar 3 at 17:08