16
\$\begingroup\$

Challenge

¡We're going to give exclamation and question marks inverted buddies!

Given a body of text containing sentences ending in ., ?, or !, prepend inverted question marks, ¿, to interrogative sentences (sentences ending in ?) and inverted exclamation marks, ¡, to exclamatory (sentences ending in !). Sentences ending in . are to be ignored.

Sentences will be separated by whitespace (spaces, tabs, and/or newlines) and will only contain alphanumerics, commas, apostrophes, and spaces. Every sentence will have at least one word. The first word of every sentence is guaranteed to be capitalized. Input can start and end with any whitespace.

Example

Input:

  Hello there!      What is your name?
My name is Ron. What's your name?
My name is Alex.  Nice to meet you!
Nice to meet you to!  How was your break?
It was great, I spent all my time code golfing!
What's that?
        Wow, you're such a n00b! Here, let me show you.

Output:

  ¡Hello there!      ¿What is your name?
My name is Ron. ¿What's your name?
My name is Alex.  ¡Nice to meet you!
¡Nice to meet you to!  ¿How was your break?
¡It was great, I spent all my time code golfing!
¿What's that?
        ¡Wow, you're such a n00b! Here, let me show you.

Rules

  • All default Code Golf rules apply.
  • The program with the shortest amount of bytes wins.

Bonus (17% off) - Parse multiple marks

A sentence can also end in multiple exclamation/question marks. Give each of these marks a paired inverse exclamation/question mark for an extra 17% off your byte count.

Example

Input:

I am a man in a can doing a dance?? Maybe...
              Doing it for the views??!???!

Output:

¿¿I am a man in a can doing a dance?? Maybe...
              ¡¿¿¿¡¿¿Doing it for the views??!???!

Incorrect output:

¿¿I am a man in a can doing a dance?? Maybe...
              ¿¿¡¿¿¿¡Doing it for the views??!???!
\$\endgroup\$
3
  • \$\begingroup\$ Do we get to choose what sort of whitespace separates the sentences, or do we have to support all 3 types? \$\endgroup\$
    – user45941
    Dec 4, 2015 at 9:00
  • \$\begingroup\$ @Mego All three types should be supported. \$\endgroup\$
    – rgajrawala
    Dec 4, 2015 at 9:01
  • \$\begingroup\$ No, a sentence will always have at least one word in it and will end with one of the three allowed punctuation characters. I'll add that to the challenge. \$\endgroup\$
    – rgajrawala
    Dec 4, 2015 at 9:04

8 Answers 8

5
\$\begingroup\$

Retina, 39 37 34 bytes

\w[^.]*?([!?])
$1$0
T`?!`¿¡`\S\b

Try it online.

Explanation

\w[^.]*?([!?])
$1$0

This matches a sentence ending in an exclamation or question mark, and prepends that punctuation character to the sentence. Now we know that all the ! or ? which are immediately followed by a non-space character must be those we inserted, because the original ones should be separated from the next character by a space.

T`!?`¡¿`\S\b

This transliteration stage turns all ! and ? into ¡ and ¿, respectively, provided they're found in a match of \S\b, which applies only to the ones we just inserted. Replacing both in two separate substitutions in the same byte count, but I prefer the semantics of a transliteration stage here.

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

Mathematica 137 bytes

Not the shortest, but it was fun to do.

TextSentences breaks up the input text into sentences and StringPosition finds the beginning and end positions of each sentence in the text. The upside down punctuation is inserted at the beginning of each sentence as required.

w=StringPosition;f[x_,y_,q_]:=StringInsert[x,q,x~w~y/.{a_,a_}->a/.(x~w~#&/@TextSentences@#&@x/.{{c_,d_}}:>d->c)];f[f[t,"!","¡"],"?","¿"]&

Usage, assuming the text is input at t,

f[f[#,"!","¡"],"?","¿"]&[t]

output

\$\endgroup\$
1
  • 1
    \$\begingroup\$ Cool, a solution that doesn't use RegExp! \$\endgroup\$
    – rgajrawala
    Dec 4, 2015 at 23:18
3
\$\begingroup\$

Sed, 61 bytes

s/\(\s*\)\([^.!?]*!\)/\1¡\2/g;s/\(\s*\)\([^.!?]*?\)/\1¿\2/g

Test run :

$ echo """Hello there!      What is your name?
My name is Ron. What's your name?
My name is Alex.  Nice to meet you!
Nice to meet you to!  How was your break?
It was great, I spent all my time code golfing!
What's that?
        Wow, you're such a n00b! Here, let me show you.""" | sed 's/\(\s*\)\([^.!?]*!\)/\1¡\2/g;s/\(\s*\)\([^.!?]*?\)/\1¿\2/g'
¡Hello there!      ¿What is your name?
My name is Ron. ¿What's your name?
My name is Alex.  ¡Nice to meet you!
¡Nice to meet you to!  ¿How was your break?
¡It was great, I spent all my time code golfing!
¿What's that?
        ¡Wow, you're such a n00b! Here, let me show you.
\$\endgroup\$
4
  • 1
    \$\begingroup\$ This is technically 61 bytes as the inverted characters count as 2 bytes. \$\endgroup\$
    – rgajrawala
    Dec 4, 2015 at 20:28
  • \$\begingroup\$ @usandfriends right, fixed \$\endgroup\$
    – Aaron
    Dec 4, 2015 at 22:38
  • \$\begingroup\$ If you use the -r flag to (GNU) sed, you don't need to escape the ( and ) which should save you 8. You do need to add an extra point for use of this non-default option though. \$\endgroup\$ Dec 4, 2015 at 23:41
  • \$\begingroup\$ @DigitalTrauma I knew that trick and tried it but it didn't return the same output : "¿¡Hello there! ¿What is your name?¿" instead of "¡Hello there! ¿What is your name?" \$\endgroup\$
    – Aaron
    Dec 5, 2015 at 1:09
3
\$\begingroup\$

Javascript (ES6), 86 79 66 63 bytes

i=>i.replace(/\w[^.!?]*[!?]/g,k=>(k.slice(-1)>'>'?'¿':'¡')+k)

Ungolfed:

func = inp => inp.replace(/\w[^.!?]*[!?]/g, sentence => (sentence.slice(-1) > '>' ? '¿' : '¡') + sentence)

Usage:

console.log(func(`Hello there!      What is your name?
My name is Ron. What's your name?
My name is Alex.  Nice to meet you!
Nice to meet you to!  How was your break?
It was great, I spent all my time code golfing!
What's that?
            Wow, you're such a n00b! Here, let me show you.`))

Will implement bonus solution soon.

Thanks to:
@user81655, 86 => 79 bytes

\$\endgroup\$
2
  • 1
    \$\begingroup\$ A few improvements which save 9 bytes: i=>i.replace(/[A-Z][^.!?]*[.!?]/g,k=>(r=k.slice(-1))<'.'?'¡'+k:r>'.'?'¿'+k:k) \$\endgroup\$
    – user81655
    Dec 4, 2015 at 12:25
  • \$\begingroup\$ @user81655 It looks like it saves 7 bytes instead of 9, but regardless, thanks for that! Was able to remove even more bytes by skipping checking for sentences ending in .. \$\endgroup\$
    – rgajrawala
    Dec 4, 2015 at 23:10
3
\$\begingroup\$

Mathematica, 101 92 91 bytes

StringReplace[#,RegularExpression@"[A-Z][^.]*?([?!])":><|"?"->"¿","!"->"¡"|>@"$1"<>"$0"]&
\$\endgroup\$
2
  • \$\begingroup\$ Would you explain how this works? \$\endgroup\$
    – DavidC
    Jan 4, 2016 at 21:17
  • 1
    \$\begingroup\$ @DavidC It's tricky. \$\endgroup\$ Jan 4, 2016 at 21:33
1
\$\begingroup\$

Python 2, 127.82 (154-17%) bytes

import re
print re.sub("([A-Z][\w ,']*)([\.!\?]+)",lambda m:''.join({'!':'¡','?':'¿','.':''}[c]for c in m.group(2))[::-1]+m.group(1)+m.group(2),input())
\$\endgroup\$
1
\$\begingroup\$

𝔼𝕊𝕄𝕚𝕟, 36 chars / 53 bytes

ïċ/\w⁅.!?]*[!?]⌿,⇏(aē-1>⍘>?⍘¿:⍘¡)+a)

Try it here (Firefox only).

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

Jelly, 41 bytes

0ị⁾!?iị“¡¿ ”t⁶
e€“!?.”kµOe€“µ½ ‘«\nƝkjÇ)F

Try it online!

Bah, who needs regex?

How it works

e€“!?.”kµOe€“µ½ ‘«\nƝkjÇ)F - Main link. Takes a string S on the left
  “!?.”                    - Yield "!?."
 €                         - For each character in S:
e                          -   Is it in "!?."?
       k                   - Split S after occurrences of any of "!?."
        µ                  - Call this list of lists of characters L and use it as the argument
                        )  - For each list of characters C in L:
         O                 -   Convert to a list of char codes
            “µ½ ‘          -   Yield [9, 10, 32]
           €               -   For each char code in C:
          e                -     Is it in [9, 10, 32]?
                               This yields 1s at whitespace characters else 0
                               However, we only want to consider leading whitespace,
                               not whitespace in the string, when inserting ¡¿
                  \        -   Scan:
                 «         -     Minimum
                               This changes all non-leading 1s to 0s
                     Ɲ     -   Over overlapping pairs:
                    n      -     Does not equal?
                               This turns the leading run of 1s into 0s with a final 1
                      k    -   Split C at this 1
                        Ç  -   Call the helper link on C
                       j   -   Join the split C on the helper link
                         F - Flatten into a single string

0ị⁾!?iị“¡¿ ”t⁶ - Helper link. Takes a list of characters C on the left
0ị             - Last character of C, c
  ⁾!?          - "!?"
     i         - Index of c in "!?" or 0 (for sentences ending with ".")
       “¡¿ ”   - "¡¿ "
      ị        - 1-index into this string. "." -> " "
             ⁶ - " "
            t  - Trim spaces. "." -> ""
\$\endgroup\$

Your Answer

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

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