44
\$\begingroup\$

Introduction

Turns out, aliens love memes just as much as we do. Every alien race we've encountered so far has their own version of 2spooky4me (see the following question) and equivalent, though, with some variation. The inhabitants of planet CUTE1f can't handle a lot of spook, so their preferred spook is 1spooky2me, while skeletor7 memers love them some spook, so they tend to use 9spooky11me.

Challenge

Translating memes is hard work, so you've been tasked with writing a universal meme translator to help these guys access the memenet correctly. Your program will accept a meme and a transformation to apply to the digit sequences in that meme to make it appropriate for the inhabitants of a different planet.

Input

Your program will receive two string inputs:

  1. The input meme (e.g. 2spooky4me). Matches [a-zA-Z0-9]+.
  2. The transformation to apply to it (e.g. +1, to go from 2spooky4me to 3spooky5me). Matches [+\-*/^]\d+ (you must accept +, -, *, /, and ^ as operators, regardless of the native representation in your language).

Output

Your program must return a string output (printed to standard output or equivalent) with the given transformation applied to the digit sequences in the input meme. In a weird turn of events, it also turns out that all races encountered so far prefer integral memes over fractional ones, so these transformations should perform integer arithmetic (e.g. 1spooky1me /2 should result in 0spooky0me).

Examples

Standard arithmetic operations apply:

Input:  2spooky4me +1
Output: 3spooky5me

Input:  2spooky4me -1
Output: 1spooky3me

Input:  2spooky4me *15
Output: 30spooky60me

Input:  10spooky900me /5
Output: 2spooky180me

Digit sequences are integral; integer truncation should occur in cases like this:

Input:  idontunderstandmemes3 /2
Output: idontunderstandmemes1

Your input may not have any digit sequences:

Input:  notreallyafunnymeme *100
Output: notreallyafunnymeme

You must support exponentiation, even if it is not a native operation in your language of choice:

Input:  2spooky4me ^3
Output: 8spooky64me

There's no limit on string length of number of digit sequences in the string:

Input:  some1meme2sequences3can4be5really6long7 /2
Output: some0meme1sequences1can2be2really3long3

Addendum

If your language supports arbitrary-precision integers as a language feature, you must use those. If it does not, you do not need to support arbitrary-precision integers. For example, you must use Integer in Haskell instead of Int because it's available as part of the language; in Java, you are not required to use BigInteger because it's a library feature, not a language feature.

Input:  2000000000000000000000000000000000000000000000000000000000000000000000000000000‌​000000000000000000000000000000000spooky4me /2
Output: 1000000000000000000000000000000000000000000000000000000000000000000000000000000‌​000000000000000000000000000000000spooky2me

This is , so standard loopholes are forbidden, and the shortest answer in bytes wins!

Leaderboard

The Stack Snippet at the bottom of this post generates the leaderboard from the answers a) as a list of shortest solution per language and b) as an overall leaderboard.

To make sure that your answer shows up, please start your answer with a headline, using the following Markdown template:

## Language Name, N bytes

where N is the size of your submission. If you improve your score, you can keep old scores in the headline, by striking them through. For instance:

## Ruby, <s>104</s> <s>101</s> 96 bytes

If there you want to include multiple numbers in your header (e.g. because your score is the sum of two files or you want to list interpreter flag penalties separately), make sure that the actual score is the last number in the header:

## Perl, 43 + 2 (-p flag) = 45 bytes

You can also make the language name a link which will then show up in the snippet:

## [><>](http://esolangs.org/wiki/Fish), 121 bytes

<style>body { text-align: left !important} #answer-list { padding: 10px; width: 290px; float: left; } #language-list { padding: 10px; width: 290px; float: left; } table thead { font-weight: bold; } table td { padding: 5px; }</style><script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <link rel="stylesheet" type="text/css" href="//cdn.sstatic.net/codegolf/all.css?v=83c949450c8b"> <div id="language-list"> <h2>Shortest Solution by Language</h2> <table class="language-list"> <thead> <tr><td>Language</td><td>User</td><td>Score</td></tr> </thead> <tbody id="languages"> </tbody> </table> </div> <div id="answer-list"> <h2>Leaderboard</h2> <table class="answer-list"> <thead> <tr><td></td><td>Author</td><td>Language</td><td>Size</td></tr> </thead> <tbody id="answers"> </tbody> </table> </div> <table style="display: none"> <tbody id="answer-template"> <tr><td>{{PLACE}}</td><td>{{NAME}}</td><td>{{LANGUAGE}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr> </tbody> </table> <table style="display: none"> <tbody id="language-template"> <tr><td>{{LANGUAGE}}</td><td>{{NAME}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr> </tbody> </table><script>var QUESTION_ID = 79809; var ANSWER_FILTER = "!t)IWYnsLAZle2tQ3KqrVveCRJfxcRLe"; var COMMENT_FILTER = "!)Q2B_A2kjfAiU78X(md6BoYk"; var OVERRIDE_USER = 45941; var answers = [], answers_hash, answer_ids, answer_page = 1, more_answers = true, comment_page; function answersUrl(index) { return "https://api.stackexchange.com/2.2/questions/" + QUESTION_ID + "/answers?page=" + index + "&pagesize=100&order=desc&sort=creation&site=codegolf&filter=" + ANSWER_FILTER; } function commentUrl(index, answers) { return "https://api.stackexchange.com/2.2/answers/" + answers.join(';') + "/comments?page=" + index + "&pagesize=100&order=desc&sort=creation&site=codegolf&filter=" + COMMENT_FILTER; } function getAnswers() { jQuery.ajax({ url: answersUrl(answer_page++), method: "get", dataType: "jsonp", crossDomain: true, success: function (data) { answers.push.apply(answers, data.items); answers_hash = []; answer_ids = []; data.items.forEach(function(a) { a.comments = []; var id = +a.share_link.match(/\d+/); answer_ids.push(id); answers_hash[id] = a; }); if (!data.has_more) more_answers = false; comment_page = 1; getComments(); } }); } function getComments() { jQuery.ajax({ url: commentUrl(comment_page++, answer_ids), method: "get", dataType: "jsonp", crossDomain: true, success: function (data) { data.items.forEach(function(c) { if (c.owner.user_id === OVERRIDE_USER) answers_hash[c.post_id].comments.push(c); }); if (data.has_more) getComments(); else if (more_answers) getAnswers(); else process(); } }); } getAnswers(); var SCORE_REG = /<h\d>\s*([^\n,<]*(?:<(?:[^\n>]*>[^\n<]*<\/[^\n>]*>)[^\n,<]*)*),.*?(\d+)(?=[^\n\d<>]*(?:<(?:s>[^\n<>]*<\/s>|[^\n<>]+>)[^\n\d<>]*)*<\/h\d>)/; var OVERRIDE_REG = /^Override\s*header:\s*/i; function getAuthorName(a) { return a.owner.display_name; } function process() { var valid = []; answers.forEach(function(a) { var body = a.body; a.comments.forEach(function(c) { if(OVERRIDE_REG.test(c.body)) body = '<h1>' + c.body.replace(OVERRIDE_REG, '') + '</h1>'; }); var match = body.match(SCORE_REG); if (match) valid.push({ user: getAuthorName(a), size: +match[2], language: match[1], link: a.share_link, }); else console.log(body); }); valid.sort(function (a, b) { var aB = a.size, bB = b.size; return aB - bB }); var languages = {}; var place = 1; var lastSize = null; var lastPlace = 1; valid.forEach(function (a) { if (a.size != lastSize) lastPlace = place; lastSize = a.size; ++place; var answer = jQuery("#answer-template").html(); answer = answer.replace("{{PLACE}}", lastPlace + ".") .replace("{{NAME}}", a.user) .replace("{{LANGUAGE}}", a.language) .replace("{{SIZE}}", a.size) .replace("{{LINK}}", a.link); answer = jQuery(answer); jQuery("#answers").append(answer); var lang = a.language; lang = jQuery('<a>'+lang+'</a>').text(); languages[lang] = languages[lang] || {lang: a.language, lang_raw: lang.toLowerCase(), user: a.user, size: a.size, link: a.link}; }); var langs = []; for (var lang in languages) if (languages.hasOwnProperty(lang)) langs.push(languages[lang]); langs.sort(function (a, b) { if (a.lang_raw > b.lang_raw) return 1; if (a.lang_raw < b.lang_raw) return -1; return 0; }); for (var i = 0; i < langs.length; ++i) { var language = jQuery("#language-template").html(); var lang = langs[i]; language = language.replace("{{LANGUAGE}}", lang.lang) .replace("{{NAME}}", lang.user) .replace("{{SIZE}}", lang.size) .replace("{{LINK}}", lang.link); language = jQuery(language); jQuery("#languages").append(language); } }</script>

\$\endgroup\$
28
  • 3
    \$\begingroup\$ Your last test case is wrong. You have one too many zeros in the output for it to be /5. \$\endgroup\$
    – anon
    May 12, 2016 at 19:14
  • 5
    \$\begingroup\$ First of all this is a reasonably well put together first post, so congrats :) Note we have a Sandbox where you can post your challenge for feedback before it goes live. \$\endgroup\$ May 12, 2016 at 19:21
  • 3
    \$\begingroup\$ Welcome to PPCG (even though you've apparently been here for 2+ years). Nice first challenge. Does the addendum about arbitrary precision integers mandate that, for example, Java must use BigInteger for its calculations? \$\endgroup\$ May 12, 2016 at 19:24
  • 19
    \$\begingroup\$ Every alien race we've encountered so far... That's totally true! :-) \$\endgroup\$
    – Luis Mendo
    May 12, 2016 at 20:48
  • 2
    \$\begingroup\$ It's your challenge and ultimately up to you, but that's not really fair towards languages that happen to use a different syntax. \$\endgroup\$
    – Dennis
    May 12, 2016 at 20:51

22 Answers 22

25
\$\begingroup\$

Ruby, 50 44 43 bytes

FGITW answer. Gotta go fast!

Thanks to @Neil for saving 6 bytes.

Oh right, crossed out 44 is still 44

->m,t{m.gsub(/\d+/){eval$&+t.sub(?^,'**')}}
\$\endgroup\$
2
  • \$\begingroup\$ Oh, man, this is almost exactly an answer I was poking away at: a=gets;$><<gets.gsub(/\d+/){eval$&+a}. Mine missed the ^ != ** thing, though, and is probably a bit longer. \$\endgroup\$
    – anon
    May 12, 2016 at 20:47
  • 3
    \$\begingroup\$ +1 for having your whole solution be 4 bytes shorter than what's needed in PowerShell just to handle ^. :D \$\endgroup\$ May 12, 2016 at 20:49
14
\$\begingroup\$

Perl, 36 34 bytes

s/\d+/"0|$&$^I"=~s#\^#**#r/gee

The source code is 30 bytes long and it requires the switches -pi (+4 bytes). It takes the first input from STDIN, the second input as an argument to -i.

Thanks to @DenisIbaev for golfing off 2 bytes!

Test it on Ideone.

\$\endgroup\$
5
  • \$\begingroup\$ Yep, I figured if anybody could beat my Ruby answer, it would be Dennis and/or be in Perl, and you ended up fulfilling both expectations at the same time \$\endgroup\$
    – Value Ink
    May 13, 2016 at 0:49
  • 1
    \$\begingroup\$ -pi is 4 bytes? \$\endgroup\$ May 13, 2016 at 20:16
  • \$\begingroup\$ @CatsAreFluffy Current consensus is to count the edit distance from the invocation without the flags. That includes a space to separate -pi from the rest of the command. \$\endgroup\$
    – Dennis
    May 13, 2016 at 20:26
  • \$\begingroup\$ "0|$&" is shorter than "0|".$&. \$\endgroup\$ May 16, 2016 at 13:50
  • \$\begingroup\$ @DenisIbaev Since the input is alphanumeric, "0|$&$^I" works too. Thanks! \$\endgroup\$
    – Dennis
    May 16, 2016 at 20:19
10
\$\begingroup\$

Jolf, 15 14 bytes

ρi«\d+»dC!6+HI

Try it here!

Explanation

ρi«\d+»dC!6+HI
ρ «\d+»         replace all digits
 i              in the input
       d        (functional replace)
         !6     eval (using jolf's custom infix eval)
           +H   the number as a string plus
             I  the second input
        C       floor the result (integer truncate)

Fun to note, I updated Jolf after this challenge, adding some RegExp builtins. This could be 12 11 bytes:

ρiLRdC!6+HI
\$\endgroup\$
9
\$\begingroup\$

PowerShell v2+, 139 137 bytes

param($a,$b)-join($a-split"(\d+)"|%{if($_-match"\d+"){if($b[0]-ne'^'){[math]::Floor((iex $_$b))}else{"$_*"*$b.Trim('^')+1|iex}}else{$_}})

Ooof ... 47 bytes just to account for ^ since that's not a native operator in PowerShell. Saved 2 bytes thanks to @TessellatingHeckler.

Takes input as $a=<word>, $b=<operation>, like .\universal-spooky-meme.ps1 2spooky4me ^3. We -split $a on digits, enclosing that in parens so we keep the delimiters, and pipe the resultant array through a loop |%{...}. If the current piece is a number, we're in the first if. We need to check whether the first character of $b is ^. If it's not, we simply concatenate our current piece and $b and send it to iex (similar to eval), then leave that on the pipeline. Otherwise, we need to create an exponentiation string with "$_*"*$b.Trim('^')+1 and pipe that to iex, and leave that on the pipeline. For the given 2spooky4me ^3 example, this will be 2*2*2*1 and 4*4*4*1, respectively.

Otherwise, we just leave the string as-is on the pipeline.

All of those results are gathered from the pipeline with the encapsulating parens before being -joined back together into one string. That is the re-left on the pipeline, and output is implicit at program termination.

Examples

PS C:\Tools\Scripts\golfing> .\universal-spooky-meme.ps1 2spooky4me ^5
32spooky1024me

PS C:\Tools\Scripts\golfing> .\universal-spooky-meme.ps1 2spooky4me /3
0spooky1me
\$\endgroup\$
2
  • \$\begingroup\$ I wrote my own before looking at answers, then I pinched some of your ideas as well - thanks. I think you could replace Floor(("$_$b"|iex)) with Floor((iex $_$b)) to save a couple, or maybe iex $_+$b. \$\endgroup\$ May 13, 2016 at 23:28
  • \$\begingroup\$ @TessellatingHeckler Thanks for the two bytes! \$\endgroup\$ May 16, 2016 at 12:30
7
\$\begingroup\$

JavaScript (ES7), 58 57 bytes

(s,t)=>s.replace(/\d+/g,n=>0|eval(n+t.replace('^','**')))

Edit: Saved 1 byte when I remembered that replace also works on literal strings.

\$\endgroup\$
3
  • \$\begingroup\$ Cool, I'm working on an ES6 solution \$\endgroup\$
    – Bálint
    May 12, 2016 at 20:11
  • \$\begingroup\$ Can you curry to save a byte? \$\endgroup\$
    – gcampbell
    May 15, 2016 at 13:17
  • 1
    \$\begingroup\$ @gcampbell Yes, but I'm too lazy to. \$\endgroup\$
    – Neil
    May 15, 2016 at 19:50
6
\$\begingroup\$

Pyth, 29

Jws.i:zK"\d+"3m.vs.iJ]+d;:zK1

This works by extracting each number from the meme, and then interleaving (.i) it followed by a space and wrapped in a list with the other argument. So if our number is 7 and we had ^20 we would get the list: ["^", "7 ", "20"]. Flattening and using Pyth's eval (.v) on this always gives the operation we want. Finally these values are interleaved with the original string split on occurrences of numbers.

This could be a byte shorter if both inputs were surrounded by quote characters, or two bytes shorter if only one of them could be quoted.

Try it here or run a Test Suite

\$\endgroup\$
6
\$\begingroup\$

Python 2, 156 89 88 87 bytes

Inspired by the other answers that use their languages' substitution function with a function handler to process the numeric parts of the long input string with the operator. Unlucky for Python, the ^ must be replaced by **, which costs a whopping 18 bytes. The .group(0) call just to access the match object's string representation does not make things better...

Thanks to QPaysTaxes for spotting a spurious space and RootTwo for the unnecessary argument to .group!

import re
lambda i,o:re.sub(r'\d+',lambda p:str(eval(p.group()+o.replace('^','**'))),i)
\$\endgroup\$
3
  • \$\begingroup\$ I think you can get rid of the space after i,o: \$\endgroup\$
    – anon
    May 12, 2016 at 20:50
  • \$\begingroup\$ You can save two more bytes: (1) by using p.group(). (it defaults to 0); and (2) insert r=re.sub; replace first re.sub call with r and then use r('^','**',o) instead of o.replace(...) \$\endgroup\$
    – RootTwo
    May 13, 2016 at 6:56
  • \$\begingroup\$ @RootTwo: For me, the r('^','**',o) then requires escaping ^ to \^ in order to match the character, not the beginning of o, net saving no bytes :-( - but thanks for pointing out the unnecessary 0! \$\endgroup\$
    – ojdo
    May 13, 2016 at 14:35
5
\$\begingroup\$

Javascript (ES6) 99 bytes

Another example, why we hate to wait for ES7 to get compatibility

(a,b)=>a.match(/\d+|\D+/g).map(_=>(d=- -_)?eval(b[0]=="\^"?Math.pow(_,b.slice(1)):d+b)|0:_).join``

Runnable example:

f=(a,b)=>a.match(/\d+|\D+/g).map(_=>(d=- -_)?Math.ceil(eval(b[0]=="\^"?Math.pow(_,b.slice(1)):d+b)):_).join``

alert(f(prompt("Enter string!"), prompt("Enter operation!")));

\$\endgroup\$
11
  • \$\begingroup\$ Your matching regexes seem to be a bit off. In the runnable example, you leave out uppercase letters, which strips them out of the result ("2spooky4ME", "+1" => "3spooky5"), and in the first example, you match against \d+|\D+, which is equivalent to .+. [a-zA-Z0-9]+ is the regex you want, no? Or [a-zA-Z]+|[0-9]+ if the splitting makes a difference? \$\endgroup\$ May 12, 2016 at 20:31
  • \$\begingroup\$ It would probably be easier to invoke Math.pow directly as you're having to special-case it anyway. Also, are you using integer division? \$\endgroup\$
    – Neil
    May 12, 2016 at 20:37
  • \$\begingroup\$ @Neil I forgot that, minute \$\endgroup\$
    – Bálint
    May 12, 2016 at 20:53
  • \$\begingroup\$ @Neil is there a better way for ceiling? \$\endgroup\$
    – Bálint
    May 12, 2016 at 21:07
  • 1
    \$\begingroup\$ @ItaiFerber \d+|\D+ Isn't quite the same as .+. They aren't the same because the kleene expansion happens before the or. It would be the same if it looked like (\d|\D)+, but as is, it wouldn't match all of say 2a in one group, it would be two separate groups. \$\endgroup\$ May 13, 2016 at 19:42
4
\$\begingroup\$

Kotlin, 416 413 Bytes

The lack of an eval() in Kotlin really upped that byte count...

fun main(a:Array<String>){var r=Regex("\\d+");var i=a[0];var n=a[1].takeLast(a[1].length-1).toInt();when(a[1][0]){'+'->print(r.replace(i,{m->""+(m.value.toInt()+n)}));'*'->print(r.replace(i,{m->""+(m.value.toInt()*n)}));'/'->print(r.replace(i,{m->""+(m.value.toInt()/n)}));'-'->print(r.replace(i,{m->""+(m.value.toInt()-n)}));'^'->print(r.replace(i,{m->""+(Math.pow(m.value.toDouble(),n.toDouble())).toInt()}));}}

Try it Online!

Ungolfed

fun main(a: Array<String>) {
    var r = Regex("""\d+""")
    var i = a[0]
    var n = a[1].takeLast(a[1].length - 1).toInt()
    when (a[1][0]) {
        '+' -> print(r.replace(i, { m -> "" + (m.value.toInt() + n) }))
        '*' -> print(r.replace(i, { m -> "" + (m.value.toInt() * n) }))
        '/' -> print(r.replace(i, { m -> "" + (m.value.toInt() / n) }))
        '-' -> print(r.replace(i, { m -> "" + (m.value.toInt() - n) }))
        '^' -> print(r.replace(i, { m -> "" + (Math.pow(m.value.toDouble(), n.toDouble())).toInt() }))
    }
}
\$\endgroup\$
4
\$\begingroup\$

PowerShell (v4), 124 120 bytes

# New 120 byte version:
$s,$a=$args;[regex]::Replace($s,'\d+',{($(if($a-ne($a=$a.Trim('^'))){
"$args*"*$a+1}else{"$args$a"})|iex)-replace'\..*'})

# Previous 124 byte version
$s,$a=$args;[regex]::Replace($s,'\d+',{if($a[0]-eq'^'){
[math]::pow("$args",$a.Trim('^'))}else{iex "$args$a-replace'\..*'"}})

(the newlines are only here to avoid horizontal scrolling, they work when saved as one line).

Comments, and ungolfed version was requested:

$meme, $instruction = $args

# Scriptblock which processes the numbers
# to be replaced. $args is the input number.
$replacement = {

    # Generates a string of the calculation, by:
    # Removing leading ^ character, if present.
    # ^3 -> 3,      +3 -> +3
    # See if it was present, and switch code paths.
    # (Can be one combined step in the golf)
    # Switch code paths for "raise to the power of",
    # or basic arithmetic.
    $trimmedInstruction = $instruction.Trim('^')
    $tmp = if ( $instruction -ne $trimmedInstruction ) {

        # String multiplication, changes
        # function input "45" and instruction "3" into
        # "45*45*45*+1". The "3" implicitly casts to [int]
        # the +1 is there to make the trailing * not crash.
        "$args*" * $instruction + 1

    } else {
        # Cobble the basic math together as a string
        # "45" and "+10" becomes
        # "45+10"
        "$args$instruction"
    }

    # eval() the generated string (e.g. "45+10" or "45*45*45*+1")
    $tmp = Invoke-Expression $tmp      # iex

    # Use a regex golf to replace trailing .23423
    # decimals in case of division with remainder.
    # Acts as [math]::floor(), harmless on other numbers.
    $tmp -replace'\..*'
}

# A regular expression replacement which picks out all 
# the numbers (\d+) and runs them through the
# replacement function. Returns a string which 
# ends up on stdout
[regex]::Replace($meme, '\d+', $replacement)
  • .Net regex library can do a replace with a scriptblock that executes on the content of the match, and PowerShell casts types strings to numbers, and iex is like eval() in other languages. It just does "2spooky" "+3" -> eval("2+3")
  • Except... it can't handle ^ operator or any other convenient exponentiation like **, it can only use the [math]::Pow() library call so there's a big block to handle that branch.
    • The updated version steals an idea from @TimmyD and does string multiplication instead - "2*" * n which becomes "2*2*2*2*" and then adds +1 on the end to multiply by one instead of complaining about the trailing *.
  • Except... .Net does Banker's Rounding which rounds to the nearest even number by default, and 3/2 = 2 rather than 3/2 = 1. This challenge calls for truncation, and that means [math]::Truncate(). Instead, I save characters by using -replace to trim a decimal point and anything after it.

Test cases:

PS D:\> .\meme.ps1 2spooky4me +1
3spooky5me

PS D:\> .\meme.ps1 2spooky4me -1
1spooky3me

PS D:\> .\meme.ps1 2spooky4me *15
30spooky60me

PS D:\> .\meme.ps1 10spooky900me /5
2spooky180me

PS D:\> .\meme.ps1 idontunderstandememes3 /2
idontunderstandememes1

PS D:\> .\meme.ps1 "idontunderstandememes3" "/2"
idontunderstandememes1

PS D:\> .\meme.ps1 "notreallyafunnymeme" "*100"
notreallyafunnymeme

PS D:\> .\meme.ps1 "2spooky4me" "^3"
8spooky64me

PS D:\> .\meme.ps1 "some1meme2sequences3can4be5really6long7" "/2"
some0meme1sequences1can2be2really3long3

PS D:\> .\meme.ps1 2000000000000000000000000000000000000000000000000000000000000000000000000000000‌​000000000000000000000000000000000spooky4me /2
1E+78‌​0spooky2me

NB. In the last test the numbers overflow into type [BigInteger] automatically, but they get rendered in scientific notation. Luckily, every known race able to communicate between the stars has enough scientific development to be able to process scientific notation without problem.

\$\endgroup\$
5
  • 1
    \$\begingroup\$ You can see in other answers how they provide a rather unreadable golfed version and then a separate ungolfed version for examining the code behavior. You should do this with yours (namely, remove the newlines in the golfed version). \$\endgroup\$
    – jpmc26
    May 16, 2016 at 7:21
  • \$\begingroup\$ Thanks for the credit, but not my trick -- I pulled it from the PowerShell Tips thread. \$\endgroup\$ May 16, 2016 at 12:31
  • \$\begingroup\$ Apparently, I care enough to leave a comment, and someone else cares enough to upvote my comment. ;) \$\endgroup\$
    – jpmc26
    May 16, 2016 at 20:39
  • \$\begingroup\$ No, I said you should have a fully golfed version and a fully ungolfed version. The golfed one will require scrolling. The ungolfed one will not and will be more readable than the one you have. \$\endgroup\$
    – jpmc26
    May 16, 2016 at 20:57
  • 1
    \$\begingroup\$ @jpmc26 Ok, I've edited in an ungolfed, commented version. \$\endgroup\$ May 18, 2016 at 17:50
4
\$\begingroup\$

Julia, 71 59 54 bytes

/ =÷
x%y=replace(x,r"\d+",t->"big($t)"y|>parse|>eval)

The requirement to use big if available makes this a lot longer than it could be...

Try it online!

\$\endgroup\$
3
\$\begingroup\$

Bash + GNU coreutils, 144 Bytes

d=
u=$1,
for((i=0;i<${#u};i++)){ l=${u:i:1}
[[ "$l" =~ [0-9] ]]&&d=$d$l||{ [ -z $d ]||echo -n `bc<<<$d$2`&&{ [ $l != , ]&&echo -n $l; };d=; }
}

This looks at the alteration between digits and non-digits, that's why a random invalid input character (comma) is appended to the input string. This comma is then ignored in the output. The convention of the OP follows exactly the syntax of bc which is used here to do the maths.

\$\endgroup\$
1
  • \$\begingroup\$ By the way because of discussion in the PowerShell-solution by @TessellatingHeckler: In my solution, you can translate the program to a single line by replacing the line breaks to semicolons, which does not change its length. \$\endgroup\$ May 17, 2016 at 17:58
3
\$\begingroup\$

Lua, 145 93 bytes

r=io.read;m=r()o=r()m=m:gsub("%d",function(n)return loadstring("return..."..o)(n)end)print(m)
\$\endgroup\$
1
  • 1
    \$\begingroup\$ Why not just post a function? \$\endgroup\$
    – Bálint
    May 13, 2016 at 8:10
3
\$\begingroup\$

Zsh (builtins only), 167 118 bytes

a=$1 S=(${(s: :)a//[0-9]/ })
for i (${(s: :)a//[a-z]/ })N+=($[i${2/^/**}])
((#a<58))&&<<<${(j::)N:^S}||<<<${(j::)S:^N}

Crack the input into a numerical array N and string array S, do operations on N, then zip the arrays together again (zip the arrays the other way if the leading character is a letter).

Try it Online.

167 bytes! (longer than the bash solution! ☹️ )

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

Zsh, 95 bytes

Whole program. Inputs: the meme and transformation as command line arguments. Output: standard output (with a trailing newline).

a=$1;repeat $#a c=${a/[^0-9]*}&&(($#c))&&b+=$[$c${2/^/**}] a=${a##<->}||b+=$a[1] a=${a#?};<<<$b

Try it online!

A 98-byte solution with a non-optimized number/letter test:

a=$1;repeat $#a [[ $a = <->* ]]&&b+=$[${a%%[^0-9]*}${2/^/**}] a=${a##<->}||b+=$a[1] a=${a#?};<<<$b

Explanation: first here's the code with additional whitespace.

a=$1;
repeat $#a \
  c=${a/[^0-9]*} &&
  (($#c)) &&
  b+=$[$c${2/^/**}] a=${a##<->} ||
  b+=$a[1] a=${a#?};
<<<$b

The general idea is to consume the input in $a from left to right, one multi-digit integer or one non-digit character at a time. Accumulate the result in $b, which is printed out after the loop.

repeat $#a … repeats the following code $#a (initial length of the input) times. The loop body consumes at least one character as long as $a is non-empty and does nothing when it runs out, so this works, and it's shorter than naive approaches such as while (($#a)) or while [ $a ]. In the loop body:

  1. Set c to the initial digit sequence of $a (remove everything starting with the first non-digit). ${a/[^0-9]*} is short for ${a/[^0-9]*/} and shorter than the more intuitive ${a%%[^0-9]*}. The assignment always succeeds, so the subsequent && is just like ; except that it doesn't terminate the repeat body.
  2. ((#c)) tests whether c is non-empty, i.e. if $a starts with a digit.
  3. If the test above, i.e. if $a starts with a digit, append the result of the arithmetic expression $[…] (an alternative form of $((…))) to b. The expression uses the digits in $c and the operator-and-number from $2. Zsh has the operators + - * / as required but exponentiation is ** instead of ^.
  4. If the test above was false, i.e. if $a starts with a non-digit, append the first character of $a to b and remove the first character from a.
\$\endgroup\$
3
\$\begingroup\$

Zsh --extendedglob, 39 bytes

<<<${1//(#m)[0-9]##/$[MATCH${2/\^/**}]}

Try it online!

\$\endgroup\$
1
  • \$\begingroup\$ This is the way. An elegant solution :) \$\endgroup\$
    – roblogic
    Oct 28, 2022 at 6:37
2
\$\begingroup\$

R, 163 bytes

As someone who's learning regular expressions and string substitution in R, this proved to be a quite difficult challenge. Especially because matching the numbers is easy but I couldn't find a way to use multiple substitutions with gsub. Furthermore, I don't know if eval(parse(paste0(... is the most efficient way to switch between operations. Maybe the switch-function is better suited here.

function(s,o){p=strsplit;y=p(gsub("\\d+","?",s),"?")[[1]];x=na.omit(as.integer(p(s,"[a-zA-Z]+")[[1]]));y[y=="?"]=floor(eval(parse(,,paste0("x",o))));cat(y,sep="")}

Explanation

f=function(s,o){
    p=strsplit                                    # alias for stringsplit    
    y=p(gsub("\\d+","?",s),"?")[[1]]              # substitute numbers with "?" and split into vector on "?"
    x=na.omit(as.integer(p(s,"[a-zA-Z]+")[[1]]))  # split at alphabetical char, return vector with numbers to be operated on
    y[y=="?"]=floor(eval(parse(,,paste0("x",o)))) # replace inserted "?" with vector of numbers operated on
    cat(y,sep="")                                 # print concatenated vector
}
\$\endgroup\$
1
  • \$\begingroup\$ I think you can save a ton of bytes if you use gsub with a closure on the matches, which is what you hinted at in your comment. I don't know how to do it in R though. I struggled with that too until I found out how to do that in Groovy; was pretty much a game changer. \$\endgroup\$ Oct 13, 2016 at 19:37
2
\$\begingroup\$

Javascript (ES6), 85 Bytes

x=(s)=>{var a=s.split(" ");return[...a[0]].map(x=>(!isNaN(x))?eval(x+a[1]):x).join``}

console.log(x("2spookie5me +1"));

Ungolfed:

x = (s) => {
  var a = s.split(" ");
  return [...a[0]].map(x => (!isNaN(x)) ? eval(x + a[1]) : x).join ``
}
console.log(x("2spookie5me +1"));
\$\endgroup\$
3
  • \$\begingroup\$ Anyone know if i can split spaces using Spread operator? From this s.split(" "); to [" "...s]; At least thats the idea. \$\endgroup\$
    – Esteru
    Oct 13, 2016 at 14:35
  • \$\begingroup\$ You don't need () around the lambda argument, you don't need var, and you should use parens and the comma operator instead of braces and return \$\endgroup\$
    – Cyoce
    Oct 13, 2016 at 18:15
  • \$\begingroup\$ Also, ^ is a special case to JavaScript, it is a bitwise XOR instead of Math.pow \$\endgroup\$
    – Sunny Pun
    Oct 13, 2016 at 18:29
2
\$\begingroup\$

Groovy, 64 60 Bytes

{a,b->a.replaceAll(/\d+/,{Eval.me(it+b.replace("^","**"))})}

Replaces all instances of digits with a closure that evaluates the operation on the digit portions of the word passed. If passed an exponent function, it replaces it with the proper notation. Groovy implicitly handles BigInteger/BigDecimal conversion when using Eval.me() because parsed strings can potentially be out of the 2^32-1 range.

Explained

{a,b->...} - Closure with two arguments.

a.replaceAll(/\d+/,{...}) - Search for all digit sequences in string and replace with a closure.

{Eval.me(it+b.replace("^","**"))} - More specifically, a closure with each match having the operation appended to it, then evaluated as groovy code.

.replace("^","**") - Replace the first instance of ^ with the groovy exponent operator ** in the operation provided. If you want this to work with full equation strings that use exponents, use replaceAll() instead for a +3 byte penalty.

Fun side-note his is a valid test scenario:
(22348952345238905290858906209862398036spooky409552me, /200*4943^8-23939+((100/203)+600)

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

05AB1E, 18 bytes

ε.γd]``s„^/„m÷‡.VJ

Input as a pair of strings.

Try it online or verify all test cases.

Explanation:

ε                  # Map both strings in the (implicit) input-pair to:
 .γ                #  Group it into substrings by:
   d               #   Is it a non-negative number
    ]              # Close both the map and inner group-by
     `             # Pop and push both list or substrings separated to the stack
      `            # Pop and push the operator and number separated to the stack
       s           # Swap them, so the operator is at the top of the stack
        „^/„m÷‡    # Transliterate "^" to "m" and "/" to "÷"
               .V  # Evaluate the operator string as 05AB1E command
                   # (the operations are no-ops on the non-number substrings)
                 J # Join the list of substrings back together to a single string
                   # (after which it is output implicitly as result)

If the final test case wasn't necessary, it could have been 17 bytes (which unfortunately has floating-point precision issues for the final test case):

ε.γd]``s'^'m:.VïJ

Try it online or verify all test cases.

Explanation:

Mostly the same as above, except for „^/„m÷‡ being '^'m: to only transform the exponent-operator and leave the division-operator as is, and the addition of ï to truncate the decimals after the eval.

\$\endgroup\$
1
  • \$\begingroup\$ 05AB1E code is pretty spooky stuff all right! \$\endgroup\$
    – roblogic
    Nov 10, 2021 at 1:05
1
\$\begingroup\$

RProgN, 39 Bytes

►x='%d+'§x'%D+'''Rx'%d+'''Rg'y'=y_}R

Explained

►x='%d+'§x'%D+'''Rx'%d+'''Rg'y'=y_}R
►                                       # Spaceless segment.
 x=                                     # Assign the top value of the stack '[+*/-]\d+' 
   '$d+'§                         }R     # Replace everything in the pattern %d+ (all numbers) based on an anonymous function 
         x'%D+'''R                      # Replace all Non-digits in the modifer with nothing, leaving just the second argument for the operator.
                  x'%d+'''R             # Snip all digits, separating our operator from our digits such that digit operator exists in the stack.
                           g'y'=        # Grab the function that is represented by the top of the stack (the operator in this case)
                                y       # Run it
                                 _      # Floor the result. 

Technically invalid answer, because this language did not exist for it. However, it was not specifically designed for it, nor any particular addition. So I'm running it. Sue me.

Try it Online!

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

Perl 6, 111 bytes

{/(\w+)\s(<[+\-*/^]>)(\d+)/&&my \b=+$2;my \o=(*+b,*-b,* *b,*div b,* **b)[index "+-*/^",$1];$0.subst(/\d+/,o):g}

Unfortunately EVAL is disabled by default. Also, you have to use div for integer division.

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