30
\$\begingroup\$

Task

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 , so fewest bytes wins!

\$\endgroup\$
12
  • 2
    \$\begingroup\$ The non-alphanumeric characters have to be ignored or can be ignored? \$\endgroup\$
    – RGS
    Apr 24, 2020 at 21:39
  • 1
    \$\begingroup\$ @RGS Thanks for the clarification question, non-alphanumeric characters must be ignored \$\endgroup\$ Apr 24, 2020 at 21:42
  • 46
    \$\begingroup\$ 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. \$\endgroup\$
    – Wheat Wizard
    Apr 24, 2020 at 23:18
  • 5
    \$\begingroup\$ Here are some posts 1 2 where you can read more about why I disagree with these extraneous elements. \$\endgroup\$
    – Wheat Wizard
    Apr 24, 2020 at 23:21
  • 9
    \$\begingroup\$ 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. \$\endgroup\$
    – S.S. Anne
    Apr 25, 2020 at 20:15

61 Answers 61

2
\$\begingroup\$

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
\$\endgroup\$
2
\$\begingroup\$

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

  • 127 bytes: removed a "." in the regex string
  • 126 bytes: replaced String.Join("" with String.Concat
  • 114 bytes: changed || to |, removed the ( ) { return; } from inside the Select
  • 112 bytes: Removed + from regex
  • 128 bytes: Reverting back to older solution. Entry now legal (thanks to @Neil and @my pronoun is monicareinstate)
  • 98 bytes: Realization that char is way more powerful than I thought (thanks to @my pronoun is monicareinstate's C# solution), removed the string -> char -> string conversions
\$\endgroup\$
5
  • 1
    \$\begingroup\$ Under standard rules this is a snippet rather than a function so you should include the (i,j,p)=>{} to make it legal, but you can at least copy the "\\W|_" that everyone else is using (with two backslashes because it's inside a string literal). Also I think i==0 can be i<1 to save another byte. \$\endgroup\$
    – Neil
    Apr 25, 2020 at 9:37
  • \$\begingroup\$ Actually you don't use j or p, so they can go too, so with the other changes you're still ahead overall. \$\endgroup\$
    – Neil
    Apr 25, 2020 at 9:38
  • \$\begingroup\$ Besides, for some weird reason you have to count using directives. While the awesome interactive compiler imports several, you still have to count using System.Text.RegularExpressions; :( \$\endgroup\$ Apr 25, 2020 at 10:09
  • \$\begingroup\$ Ah Neil, thanks, I will change it. \$\endgroup\$
    – KaleSurfer
    Apr 26, 2020 at 0:59
  • \$\begingroup\$ @ my pronoun is monicareinstate do you have a link for more info on that rule? Thanks \$\endgroup\$
    – KaleSurfer
    Apr 26, 2020 at 1:02
2
\$\begingroup\$

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!

\$\endgroup\$
2
\$\begingroup\$

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!

\$\endgroup\$
2
  • 1
    \$\begingroup\$ \x->zip x$tail x is zip<*>tail for four bytes of savings. \$\endgroup\$ Apr 25, 2020 at 23:02
  • \$\begingroup\$ uncurry$(.pure).(:) is \(a,b)->[a,b] for another six. \$\endgroup\$ Apr 25, 2020 at 23:03
2
\$\begingroup\$

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 
\$\endgroup\$
2
\$\begingroup\$

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!

\$\endgroup\$
10
  • \$\begingroup\$ 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);}} \$\endgroup\$
    – JustinCB
    Apr 25, 2020 at 15:17
  • \$\begingroup\$ 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) \$\endgroup\$
    – JustinCB
    Apr 25, 2020 at 15:19
  • \$\begingroup\$ 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);}}} \$\endgroup\$
    – JustinCB
    Apr 25, 2020 at 15:24
  • \$\begingroup\$ Cool, thanks! I'll update the answer. \$\endgroup\$
    – sugarfi
    Apr 25, 2020 at 15:36
  • \$\begingroup\$ I don't think outputting null bytes is allowed. Also, you can remove i; and use a instead. \$\endgroup\$
    – S.S. Anne
    Apr 25, 2020 at 20:06
2
\$\begingroup\$

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!

\$\endgroup\$
2
\$\begingroup\$

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.

\$\endgroup\$
2
\$\begingroup\$

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" "
\$\endgroup\$
2
\$\begingroup\$

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
\$\endgroup\$
2
\$\begingroup\$

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
\$\endgroup\$
2
\$\begingroup\$

Lua, 57 bytes

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

Try it online!

Performs three steps:

  • Removes all non-alphanumerics

    Blurry vision -> Blurryvision

  • Double all characters, with a space in between

    Blurryvision -> B Bl lu ur rr ry yv vi is si io on n

  • Remove the excess characters

    B Bl lu ur rr ry yv vi is si io on n -> Bl lu ur rr ry yv vi is si io on

\$\endgroup\$
1
\$\begingroup\$

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!

\$\endgroup\$
1
\$\begingroup\$

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)'

    """)
}
```
\$\endgroup\$
1
\$\begingroup\$

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

\$\endgroup\$
1
\$\begingroup\$

Java (JDK), 59 bytes

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

Try it online!

\$\endgroup\$
0
1
\$\begingroup\$

PowerShell Core, 48 47 bytes

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

Try it online!

\$\endgroup\$
1
\$\begingroup\$

APL (NARS2000 dialect) 24 bytes

{¯1↓1↓⍕2,/⍵/⍨⍵∊A←⎕a,⎕A,⎕D}
\$\endgroup\$
0
1
\$\begingroup\$

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

\$\endgroup\$
1
\$\begingroup\$

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

\$\endgroup\$
5
  • 1
    \$\begingroup\$ Or -3 more bytes if you use .flat_map(|c|[c,' ',c]) instead \$\endgroup\$
    – mousetail
    Oct 17, 2022 at 12:04
  • 1
    \$\begingroup\$ Consider using ATO instead of TIO which has more up to date versions of many major languages \$\endgroup\$
    – mousetail
    Oct 17, 2022 at 12:13
  • 1
    \$\begingroup\$ 103 bytes: |s|{let a:String=s.filter(|c|c.is_alphanumeric()).flat_map(|c|[c,' ',c]).collect();a[2..a.len()-2].into()}, usable as a fn(&mut std::vec::IntoIter<char>) -> String \$\endgroup\$
    – corvus_192
    Oct 17, 2022 at 17:15
  • \$\begingroup\$ Thanks @corvus_192! When you say 103 bytes, how are you counting them? I get it to 106. \$\endgroup\$
    – JSorngard
    Oct 18, 2022 at 9:17
  • \$\begingroup\$ You're right it's 106. I think I had some version with 103 bytes, but I can't remember . \$\endgroup\$
    – corvus_192
    Oct 19, 2022 at 6:36
1
\$\begingroup\$

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: \

\$\endgroup\$
1
\$\begingroup\$

Vyxal, 5 bytes

kr↔zṄ

Try it Online!

kr↔   # Remove non-alphanumeric
   z  # Get chunks of length 2
    Ṅ # Join with spaces
\$\endgroup\$
5
  • \$\begingroup\$ 20 bytes: Try it Online! \$\endgroup\$ Jun 5, 2021 at 13:30
  • \$\begingroup\$ @astonearachnid Thanks! Building on that, I got to 15 bytes. \$\endgroup\$
    – emanresu A
    Jun 6, 2021 at 1:39
  • \$\begingroup\$ Try it Online! for 10 \$\endgroup\$
    – lyxal
    Jun 6, 2021 at 3:58
  • \$\begingroup\$ Try it Online! for 7 \$\endgroup\$
    – lyxal
    Jun 6, 2021 at 3:59
  • \$\begingroup\$ now 5 bytes \$\endgroup\$
    – lyxal
    Mar 31, 2023 at 12:51
1
\$\begingroup\$

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.

\$\endgroup\$
1
  • \$\begingroup\$ It looks like calling a function BMP on an object _ lol \$\endgroup\$
    – noodle man
    Mar 6 at 22:50
1
\$\begingroup\$

Scala 3, 75 bytes

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

Attempt This Online!

\$\endgroup\$
1
\$\begingroup\$

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!

\$\endgroup\$
1
\$\begingroup\$

Uiua, 22 bytes

/$"_ _"◫2▽+⌵⊃±∊,+@0⇡10

Try it

-1 + fix thanks to chunes :)

Explanation:

+@0⇡10

Take each number 0 to 9 and convert to character by adding it to character literal 0

⊃±∊,

Apply sign ± to each character of the input, and member ∊ to the digit list and each character of the input. The former gives 0 for non-letters, 1 for uppercase letters, and -1 for lowercase letters. The latter gives 1 if the character is a digit and 0 otherwise.

+⌵

Take the absolute value of each result from sign ±, yielding a list of 1 and 0. Then, add this list to the results of member ∊. This results in a list with 1 at every position where there's a letter or a digit, and 0 everywhere else.

keep ▽ takes two lists and, in the case of the top containing only 0's and 1's, acts as a filter, removing any items from the first list that correspond with a 0 in the second. Here, the first list is the input string, and the second list is the filter created above.

So far, everything has just been the task of removing non-alphanumeric characters. The main task itself is much shorter:

◫2

The size-2 windows ◫ of the list. This gives the overlapping pairs of the string.

/$"_ _"

reduce / passes the first two items through a function, then that result and the next item through the same function, repeatedly until there are no more items left. $"_ _" is a format string, which becomes a function where each _ becomes replaced with an item from the stack. This operation results in the list joined by spaces.

\$\endgroup\$
3
  • \$\begingroup\$ You also need to get rid of underscores, which inconveniently are matched by the \w regex. \$\endgroup\$
    – DLosc
    Mar 7 at 5:08
  • \$\begingroup\$ -1 without the underscore problem. \$\endgroup\$
    – chunes
    Mar 7 at 7:06
  • \$\begingroup\$ @chunes thanks! That’s close to what my original idea was but a bit shorter \$\endgroup\$
    – noodle man
    Mar 7 at 12:56
0
\$\begingroup\$

PowerShell Core, 56 bytes

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

Try it online!

-20 bytes for @mazzy

\$\endgroup\$
3
  • \$\begingroup\$ nice. you don't need $s. see Try it online! \$\endgroup\$
    – mazzy
    Mar 2, 2021 at 10:06
  • \$\begingroup\$ @mazzy thanks for it! \$\endgroup\$
    – Wasif
    Mar 2, 2021 at 10:07
  • \$\begingroup\$ Wasif, I think improvements are needed here. See test case Blurry vision \$\endgroup\$
    – mazzy
    Mar 2, 2021 at 10:11
0
\$\begingroup\$

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!

\$\endgroup\$
0
\$\begingroup\$

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
\$\endgroup\$
0
\$\begingroup\$

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
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.