17
\$\begingroup\$

You are given a string and two characters. You have to print the string between these characters from the string.

Input

Input will first contain a string (not empty or null). In the next line, there will be two characters separated by a space.

Challenge

Return the string between the two characters

Example

Hello! What's your name?
! ?

should result in the output:

" What's your name"

Rules

  • The string will not be longer than 100 characters and will only contain ASCII characters in range (space) to ~(tilde) (character codes 0x20 to 0x7E, inclusive). See ASCII table for reference.
  • You must take input from the stdin( or closest alternative ).
  • The output should be surrounded with quotes(").
  • You can write a full program, or a function which takes input, and outputs the final string
  • The two characters will only contain ASCII characters in range (space) to ~(tilde) (character codes 0x20 to 0x7E, inclusive). See ASCII table for reference.
  • There is no guarantee that both the characters will be in the string.
  • If any of the characters is not found in the string, print "null".
  • If any of the characters is found more than one times (unless both the characters are same) in a string, print "null".
  • If both the characters are the same character, print the string "null".

Test Cases

1)

<HTML>code</HTML>
> <                       --> "null"

2)

What's what?
' '                       --> "null"

3)

abcdefghijklmnopqrstuvwxyz
n k                       --> "lm"

4)

Testing...
e T                       --> ""

5)

Last test-case
  -                       --> "test"

Scoring

This is code golf, so the shortest submission (in bytes) wins.

\$\endgroup\$
  • 3
    \$\begingroup\$ Can the characters occur in the opposite order in the string? If so, that could use a test case. \$\endgroup\$ – Martin Ender May 18 '15 at 12:45
  • 1
    \$\begingroup\$ What if the substring contains a "? Should we just surround it with another pair of quotes and not care about that? \$\endgroup\$ – jimmy23013 May 18 '15 at 12:48
  • \$\begingroup\$ @MartinBüttner , Yes. See edited test case 3. Thanks for reminding me about that \$\endgroup\$ – Spikatrix May 18 '15 at 12:56
  • \$\begingroup\$ @user23013 , Yes. Example input: one"two-three \n" - output: "two" (\n is a newline) \$\endgroup\$ – Spikatrix May 18 '15 at 12:57
  • 1
    \$\begingroup\$ I'm not a fan of the fiddly details about the markers not appearing or appearing multiple times. I think the problem would be more enjoyable to solve with stronger guarantees on the inputs. \$\endgroup\$ – xnor May 19 '15 at 5:40

12 Answers 12

3
\$\begingroup\$

CJam, 34 33 32 bytes

'"l_l2%&2*2>NerN/0"null"t_,3=='"

Try it online in the CJam interpreter.

Idea

  1. Remove the second character from line 2.

  2. Form a string consisting of a single copy of all characters that both lines have in common.

  3. Repeat the resulting string twice and discard its first two characters.

    This results in a two-character string (if the characters from line 2 are different and both occur in line 1) or an empty string.

  4. Replace the characters of the resulting string in line 1 by linefeeds.

  5. Split line 1 at linefeeds.

    The resulting array's second element will be the desired string if the array contains exactly three chunks.

  6. Replace the first element of the array with the string null.

  7. Retrieve the second element of the array if its length is 3 and the first otherwise.

  8. Prepend and append a double quote.

Code

'"       e# Push a double quote.
l_       e# Read one line from STDIN. Push a copy.
l2%      e# Read one line from STDIN. Only keep characters at odd indexes.
&        e# Intersect both strings.
2*2>     e# Repeat the intersection twice and discard the first two characters.
Ner      e# Replace the characters of the resulting string with linefeeds.
N/       e# Split the result at linefeeds.
0"null"t e# Replace the first element of the resulting array with "null".
_,3=     e# Push 1 if the length of the array is 3 and 0 otherwise.
=        e# Retrieve the corresponding element from the array.
'"       e# Push a double quote.
\$\endgroup\$
2
\$\begingroup\$

CJam, 38 bytes

l:Tl2%f#_W-$2,=2,@f#$~T<>1>"null"?'"_o

Too long...

Explanation

l:T             e# Read a line and store in T.
l2%             e# Read the two characters into a list.
f#              e# Find each character in the list of two characters.
_W-             e# Copy and remove not found results.
$2,=            e# Sort and check if the result is exactly [0 1].
                e# If true:
2,@f#           e# Find 0 and 1 in the original results.
$               e# Sort.
~T<>            e# Get a slice of T between the two positions (left-closed).
1>              e# Remove the first character.
                e# If false:
"null"          e# The string "null".
?               e# End if.
'"_o            e# Append a quote and output another quote at the beginning.
\$\endgroup\$
2
\$\begingroup\$

Pyth, 37 36 34 bytes

p?"null"njT9m/zd{J%2wt:z.uSmxzdJNN

Thanks to @isaacg for the two bytes save.

Try it online: Pyth Compiler/Executor

Explanation:

                                     implicit: z = first input line
                    w                second input line
                  %2                 only use every 2nd char
                 J                   and store in J
                {J                   set(J), gets rid of duplicates
            m/zd                     count the number of appearances of each char
        njT1                         != [1, 1] ([1,1] is 10 in base 9)
 ?      njT1m/zd{J%2w                ... if [1,1] != number of appearances else ...
  "null"                               string "null"
                           mxzdJ     find the index for each char
                          S          sort the indices
                      :z.u           take the substring of z using these indices
                     t               remove the first char

p                               NN  print '"' + ... + '"'
\$\endgroup\$
  • \$\begingroup\$ *2]1 is shorter than [1 1), and - ... 1 is shorter still. \$\endgroup\$ – isaacg May 19 '15 at 16:05
  • \$\begingroup\$ @isaacg -...1 don't work, since I also need to check that there are exactly two numbers. \$\endgroup\$ – Jakube May 19 '15 at 16:11
  • 2
    \$\begingroup\$ I just thought of a 3 character way to make [1 1): jT9. \$\endgroup\$ – isaacg May 19 '15 at 16:14
2
\$\begingroup\$

Python 3, 149 bytes

s,i=input(),input();a,b=s.find(i[0]),s.find(i[2]);print('"'+('null',[s[a+1:b],s[b+1:a]][b<a])[(s.count(i[0])==s.count(i[2])==1)*(a!=b)*(a*b>-1)]+'"')

Ungolfed Version:

string, chars = input(), input()
a, b = string.find(chars[0]), string.find(chars[2])

    if string.count(chars[0]) == string.count(chars[2]) == 1 and a!=b and a*b>-1:
        if b<a:
            print('"' + string[b+1:a] + '"')
        else:
            print('"' + string[a+1:b] + '"')
else:
    print('"null"')

This is my first answer here, so tips and criticism are much appreciated.

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

Ruby, 108 95 94

->s,f,l{a,b=[f,l].map{|u|(f==l||s.count(u)>1)&&abort('"null"');s.index u}.minmax;p s[a+1...b]}

And for the ungolfed version

def between(string, first, last)
    left, right = [first, last].map do |substring|
        abort('"null"') if first == last || string.count(substring) != 1
        string.index(substring)
    end.minmax
    p string[left + 1 ... right]
end
\$\endgroup\$
  • \$\begingroup\$ Why can't I see any output when I run your code here? \$\endgroup\$ – Spikatrix May 20 '15 at 8:47
  • \$\begingroup\$ @CoolGuy It is an unnamed function, so you need to call it like this ->s,f,l{begin a,b=[f,l].map{|u|raise if f==l||s.count(u)>1;s.index u}.minmax;p s[a+1...b];rescue;p'null'end}["<html>test</html>",?>,?<] The [...] at the end is what calls the function. \$\endgroup\$ – blutorange May 20 '15 at 11:13
  • \$\begingroup\$ @blutorange , Ok. That sort-of worked, but how do I test the last test case? \$\endgroup\$ – Spikatrix May 20 '15 at 11:17
  • \$\begingroup\$ @CoolGuy Use normally quoted strings: ->s,f,l{begin a,b=[f,l].map{|u|raise if f==l||s.count(u)>1;s.index u}.minmax;p s[a+1...b];rescue;p'null'end}["Last test-case"," ","-"] \$\endgroup\$ – blutorange May 20 '15 at 11:43
  • \$\begingroup\$ Instead of raising an error with raise, you can replace raise with an undefined variable such as _ or y. This raises a NameError. Also, I think you could save a few more bytes without an explicit rescue: ->s,f,l{a,b=[f,l].map{|u|(f==l||s.count(u)!=1)&&p('null')&&exit;s.index u}.minmax;p s[a+1...b]} \$\endgroup\$ – blutorange May 20 '15 at 12:03
1
\$\begingroup\$

C, 192 bytes

f(){char b[101],c,d,*p,*t;scanf("%[^\n]%*c%c%*c%c",b,&c,&d);p=strchr(b,c);t=strchr(b,d);c==d||!p||!t||strchr(p+1,c)||strchr(t+1,d)?puts("\"null\""):printf("\"%s\"",p<t?(*t=0,p+1):(*p=0,t+1));}

Ungolfed code:

f()
{
    char b[101],c,d,*p,*t; //Variables

    scanf("%[^\n]%*c%c%*c%c",b,&c,&d); //Scan input

    p=strchr(b,c);
    t=strchr(b,d); //Find occurrence of characters

    c==d         ||  //If both characters are the same
    !p           ||  //If no occurrence of first character found
    !t           ||  //If no occurrence of second character found
    strchr(p+1,c)||  //If two occurrence of first character found
    strchr(t+1,d) ?  //If two occurrence of second character found
    puts("\"null\"") //Print "null"
                  :  //else
    printf("\"%s\"",p<t?(*t=0,p+1):(*p=0,t+1)); //print the string
}

Test it here

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

Python 3, 172 bytes

x=input()
a=input()
a,b=a[0],a[2]
if(a!=b)&(x.count(b)==x.count(a)==1):
 if x.index(a)>x.index(b):q=a;a=b;b=q
 print('"'+x.split(a)[1].split(b)[0]+'"')
else:print('"null"')
\$\endgroup\$
1
\$\begingroup\$

Javascript (ES6), 125 123 bytes

Idea stolen heavily from @edc65's solution.

[a,,b]=(p=prompt)(s=p()),[,c,d,e,,f]=s.split(RegExp('(['+(a+b).replace(/\W/g,'\\$&')+'])'))
p('"'+(!e||f||c==e?null:d)+'"')

\$\endgroup\$
  • \$\begingroup\$ I mostly like [a,,b]=, I'll use it next time. As regexs are a hassle, here is a regex free solution: [a,,b]=(P=prompt)(s=P()), P((s=s.split(a)).length==2& (s=[].concat(...s.map(s=>s.split(b)))).length==3 ?``"${s[1]}"``:null) \$\endgroup\$ – edc65 May 19 '15 at 8:00
  • \$\begingroup\$ (the last string is templated, difficult to put in a comment) \$\endgroup\$ – edc65 May 19 '15 at 8:02
1
\$\begingroup\$

Python, 161 bytes

import re,sys
s,p=sys.stdin
m=re.match('[^%s]*([%s])([^%s]*)([%s])[^%s]*$'%((p[0]+p[2],)*5),s)
if m:g=m.group
print'"null"'if not m or g(1)==g(3)else'"'+g(2)+'"'

The solution mostly just uses a regular expression to extract the string. To accommodate that the letters could match in either direction, the start and end of the matched part allows either letter. Checking that the letters that actually matched to be different excludes the same letter being matched twice, as well as the two letters in the input being the same.

This is my first attempt at using Python for an answer here. So feedback on possible improvements is very welcome. I particularly have a feeling that there must be a way to make the condition in the print statement shorter.

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

Python 3, 155 bytes

s,n,a,b=[input(),'null']+list(input())[::2];q,w=[s.find(a),s.find(b)];print('"'+{0>1:n,0<1:s[min(q,w)+1:max(q,w)],a==b:n}[s.count(a)==s.count(b)==1]+'"')

Try it online

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

golflua, 132 bytes

L=I.r()I,J=I.r():m("(.) (.)")i=L:f(I)j=L:f(J)K,c=L:g(I,'')_,b=K:g(J,'')?i>j i,j=j,i$w((i==j|c+b!=2)&'"null"'|'"'..L:s(i+1,j-1)..'"')

Pretty ugly answer. The input bit is a bit rough (and requires two lines, first with the string & second with the slice characters ). Finding the locations of the flags is straight-forward, but just too long to compete with other answers. Output is pretty easy. An equivalent Lua program would be

Line1 = io.read()
Line2 = io.read()
I,J = Line2:match("(.) (.)")     -- boobs return the char flags
i = Line1:find(I)                -- find location of flags
j = Line1:find(J)
K,c = Line1:gsub(I,'')           -- replace flag w/ empty & store in K
_,b = K:gsub(J,'')               -- taking K ensures single flags fail
if i > j then i,j=j,i end        -- ensure we start low to high
if i==j or not (c+b == 2) then   -- if i & j are the same or not 2 counts, fail
   print('"null"')
else                             -- print the string otherwise
   print('"'..Line1:sub(i+1,j-1)..'"')
end
\$\endgroup\$
  • \$\begingroup\$ Is there any online compiler which I can test the golfed version? \$\endgroup\$ – Spikatrix May 21 '15 at 8:29
  • \$\begingroup\$ I don't believe there's an online version, but the source code is available. It is a 1:1 mapping of Lua (not an interpretation or translation to Lua), so the Lua code can be tested at ideone. \$\endgroup\$ – Kyle Kanos May 21 '15 at 11:08
0
\$\begingroup\$

Perl, 65

#!perl -p0
$.*=s/\Q$1/
/g while s/ ?(.)\z//;/
(.*)
/;$_=$.-1?null:"\"$1\""

This requires there is no newline character at in the second line of the input.

\$\endgroup\$
  • \$\begingroup\$ Nice job. This seems to be missing the double quotes though. \$\endgroup\$ – Dennis May 19 '15 at 18:41
  • \$\begingroup\$ @Dennis, fixed. I misunderstood the example. \$\endgroup\$ – nutki May 19 '15 at 20:11
  • 1
    \$\begingroup\$ It's still missing the quotes for the null case. \$\endgroup\$ – Dennis May 19 '15 at 20:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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