# Select the word around the given index in a given string

In Windows, when you perform double-click in a text, the word around your cursor in the text will be selected.

(This feature has more complicated properties, but they will not be required to be implemented for this challenge.)

For example, let | be your cursor in abc de|f ghi.

Then, when you double click, the substring def will be selected.

# Input/Output

You will be given two inputs: a string and an integer.

Your task is to return the word-substring of the string around the index specified by the integer.

Your cursor can be right before or right after the character in the string at the index specified.

# Specifications (Specs)

The index is guaranteed to be inside a word, so no edge cases like abc |def ghi or abc def| ghi.

The string will only contain printable ASCII characters (from U+0020 to U+007E).

The word "word" is defined by the regex (?<!\w)\w+(?!\w), where \w is defined by [abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_], or "alphanumeric characters in ASCII including underscore".

The index can be 1-indexed or 0-indexed.

# Testcases

The testcases are 1-indexed, and the cursor is right after the index specified.

The cursor position is for demonstration purpose only, which will not be required to be outputted.

string    index     output    cursor position
abc def   2         abc       ab|c def
abc def   5         def       abc d|ef
abc abc   2         abc       ab|c abc
ab cd ef  4         cd        ab c|d ef
ab   cd   6         cd        ab   c|d
ab!cd     1         ab        a|b!cd

• Can the string contain newlines?
– orlp
Jul 18, 2016 at 15:04
• @orlp The challenge was edited to restrict the input to printable ASCII so the input will not contain newlines. Jul 18, 2016 at 15:15
• Your testcases do not contain any other delimiters than spaces. What about a word like we're?
– orlp
Jul 18, 2016 at 15:27
• What should "ab...cd", 3 return? Jul 18, 2016 at 16:22
• @Titus "The index is guaranteed to be inside a word" Jul 18, 2016 at 16:26

# V, 10, 9 7 bytes

À|diwVp


Try it online!

This could be shorter if we do exactly what the title says: "Select the word around the given index in a string". We could do

À|viw


Which literally selects the word, but unfortunately doesn't change the output at all. So we need a little workaround to make it work by cutting it into a register, deleting the rest of the text, then pasting the register back in.

Explanation:

À|          " Jump the position of argument 1
diw       " (d)elete (i)nside this (w)ord.
V      " Select this line
p     " And replace it with the word we just deleted


# C, 104 bytes

p[99];i,d;main(l){for(scanf("%d",&i);scanf("%[^a-zA-Z0-9_]%[a-zA-Z0-9_]%n",&d,&p,&l),i>l;i-=l);puts(p);}


Expects the input on stdin to be the 0-based index followed by one space or newline, followed by the string. Maximal length for a word is 99 characters. E.g.:

2 abc def

• It's really cool to see C and perl tied on a string based challenge. :D Jul 18, 2016 at 15:26
• Can the input string have longer than 100 characters? Jul 18, 2016 at 15:27
• @LeakyNun Yes, but one word can not be longer than 100 characters.
– orlp
Jul 18, 2016 at 15:27
• Do you feel like putting that requirement inside your answer? Jul 18, 2016 at 15:28
• @DrGreenEggsandIronMan Too bad I had to fix my answer because it was delimited on whitespace :(
– orlp
Jul 18, 2016 at 15:36

# C (gcc), 94 bytes

f(n,p)char*p;{for(p+=n-1;isalnum(*p)|*p==95&&n--;--p);for(;isalnum(*++p)|*p==95;putchar(*p));}


Zero-indexed, defines a function taking the index, then the string.

• I think isalnum(*++p)|*p==95 is undefined behavior. Jul 18, 2016 at 17:06
• @owacoder It is, but what matters is that gcc spits out an executable that works. *++p^95?isalnum(*p):1 is one byte longer, but works on every compiler.
– orlp
Jul 18, 2016 at 17:07
• I assume the leading space is a typo? Also, here's a lazy IDEone link. Jul 18, 2016 at 17:11
• isalnum(*++p)||*p==95 also works, for an added one byte. Jul 18, 2016 at 17:12
• @FryAmTheEggman Yes it is, fixed now.
– orlp
Jul 18, 2016 at 17:13

## Retina, 22

(1)+¶(?<-1>.)*\b|\W.+



Try it online! or verify all test cases. The regular program takes the cursor position in unary followed by a newline and then the string. The test suite has additional code to run in per line mode, and uses a \ as a delimiter, and it uses decimal, for convenience.

Uses balancing groups to find the cursor position, then backtracks up to a word boundary. Deletes the text up to the word, and then after the word.

# Pyth, 16 bytes

+e=:.<+QbE"\W"3h

Q            first input (string)
+ b           plus newline
.<   E          rotate left by second input (number)
:      "\W"3     split on regex \W, non-word characters
=                 assign to Q
e                  last element
+              hQ   plus first element


Try it online

# JavaScript (V8), 44 bytes

(i,x)=>RegExp(\\w*(?<=.{${i}})).exec(x)[0]  Try it online! This is longer than an existing JS solution, but I don't actually understand the approach it uses, and I wrote this prior to seeing that solution. Hopefully this is different enough to be interesting :P Code explanation, so the same fate is not befallen upon ye (i,x)=> take i (number) and x (string) RegExp(...${i}...)             construct a regex with i in it
.exec(x)[0]  return the first result of that regex on the string

\w*(?<=.{i}) constructed regex
\w*          match an entire word
(?<=    ) if the end of the word comes after
.{i}  at least i characters

• 43 bytes if you curry but who really cares Oct 6, 2022 at 13:50

# C, 115 bytes

Function f() requires the string and index (1-indexed) as parameters and prints the result to stdout. Cursor should be after the specified character.

f(char*p,int n){char*s=p+n;for(;s>=p&&isalnum(*s)+(*s==95);--s);for(p=s+1;*p&&isalnum(*p)+(*p==95);putchar(*p++));}


f=(s,n)=>s.slice(0,n).match(/\w*$/)+s.slice(n).match(/\w*/)  Simply slices the string at the cursor point (which is before the 0-indexed character, which works out the same as after the 1-indexed character), then extracts and concatenates the adjacent word fragments. Even returns a sensible result when the cursor is at the start, end, or nowhere near a word. • Do you need the * in the last regex? Jul 18, 2016 at 17:31 • @CharlieWynn Yes, otherwise the second testcase would only return de. – Neil Jul 18, 2016 at 17:37 • whoops, got unlucky with the tests I ran Jul 18, 2016 at 17:39 # Java 8, 86 78 bytes (s,p)->{for(String t:s.split("\\W"))if((p-=t.length()+1)<0)return t;return"";}  Ungolfed with test cases: class Indexer { public static String f(String s, int p) { for(String t : s.split("\\W")) if((p -= t.length()+1) < 0) return t; return ""; } public static void main(String[] args) { System.out.println(f("abc def",2)); System.out.println(f("abc def",5)); System.out.println(f("abc abc",2)); System.out.println(f("ab cd ef",4)); System.out.println(f("ab cd",6)); System.out.println(f("ab!cd",1)); } }  Splits the string by non-alphanumeric characters, then keeps subtracting the length of each substring, plus 1, from the specified position, until it becomes negative. Since any repeating non-alphanumerics get represented as empty string, the subtraction logic is significantly easier. This code isn't extensively tested, so I'd like to see if someone can break this. Also, considering that this is Java code, how is this not the longest answer here? :P • I know it's been almost three years, but (s,p)-> can be s->p-> by using a currying lambda expression (i.e. java.util.function.Function<String, java.util.function.Function<String, String>> f). In addition, String could be var now if switched to Java 10, although that wasn't available at the time of course. Regardless, nice answer. I see I've already updated it somewhere in the past. :) Mar 15, 2019 at 10:40 # Ruby, 41 31 bytes Try it online! -10 bytes from @MartinEnder ->s,i{s[/\w*(?<=^.{#{i}})\w*/]}  ## Pyke, 19 bytes #Q;cjmli<i+s)lttjR@  Try it here! Uses Q; as a no-op to make sure the first input is placed correctly # ) - first where c - input.split() ml - map(len, ^) i< - ^[:i] i+ - ^+[i] s - sum(^) lt - len(^)-2  • I'm having a 504 error when I click your link. Jul 18, 2016 at 17:32 • @LeakyNun Yeah, I killed it by accident whilst writing which is why I had the localhost link, it'll come back – Blue Jul 18, 2016 at 17:36 • Try it here! Jul 19, 2016 at 7:56 • Your program seems to be outputting N where the Nth word is the one selected, but we need the full word Jul 19, 2016 at 9:33 # Python 2, 70 66 bytes import re f=lambda x,y,r=re.split:r('\W',x[:y])[-1]+r('\W',x[y:])[0]  Splits the string by non-word separators, once on the original string up to the cursor index, then on the string beginning at the cursor index. Returns the last element of the left split plus the first element of the right split. Thanks to Leaky Nun for saving 4 bytes! # Clojure, 92 bytes (fn[x k](let[[u i](map #(re-seq #"\w+"(apply str %))(split-at k x))](str(last u)(nth i 0))))  First, splits input string at position k into two strings. Then for these strings find occurrences of "\w+" and return them as list. Then concatenate the last element of first list and the first element of second list. See it online: https://ideone.com/Dk2FIs # JavaScript (ES6), 52 bytes (s,n)=>RegExp(^.{0,${n}}(\\W+|^)(\\w+)).exec(s)[2]


const F = (s,n) => RegExp(^.{0,{n}}(\\W+|^)(\\w+)).exec(s)[2] class Test extends React.Component { constructor(props) { super(props); const input = props.input || ''; const index = props.index || 0; this.state = { input, index, valid: /\w/.test(input), }; } onInput = () => { const input = this.refs.input.value; const index = Math.min(+this.refs.index.value, input.length); this.setState({ input, index, valid: /\w/.test(input), }); } render() { const {input, index, valid} = this.state; return ( <tr> <td>{ this.props.children }</td> <td> <input ref="input" type="text" onInput={this.onInput} value={input} /> <input ref="index" type="number" onInput={this.onInput} min="1" max={input.length} value={index} /> </td> {valid && [ <td>{F(input, index)}</td>, <td><pre>{input.slice(0, index)}|{input.slice(index)}</pre></td>, ]} </tr> ); } } class TestList extends React.Component { constructor(props) { super(props); this.tid = 0; this.state = { tests: (props.tests || []).map(test => Object.assign({ key: this.tid++ }, test)), }; } addTest = () => { this.setState({ tests: [...this.state.tests, { key: this.tid++ }], }); } removeTest = key => { this.setState({ tests: this.state.tests.filter(test => test.key !== key), }); } render() { return ( <div> <table> <thead> <th/> <th>Test</th> <th>Output</th> <th>Diagram</th> </thead> <tbody> { this.state.tests.map(test => ( <Test key={test.key} input={test.input} index={test.index}> <button onClick={() => this.removeTest(test.key)} style={{ verticalAlign: 'middle', }}>-</button> </Test> )) } </tbody> <tfoot> <td/> <td> <button onClick={this.addTest} style={{ width: '100%', }}>Add test case</button> </td> </tfoot> </table> </div> ); } } ReactDOM.render(<TestList tests={[ { input: 'abc def', index: 2 }, { input: 'abc def', index: 5 }, { input: 'abc abc', index: 2 }, { input: 'ab cd ef', index: 4 }, { input: 'ab cd', index: 6 }, { input: 'ab!cd', index: 1 }, ]} />, document.body); input[type="number"] { width: 3em; } table { border-spacing: 0.5em 0; border-collapse: separate; margin: 0 -0.5em ; } td, input { font-family: monospace; } th { text-align: left; } tbody { padding: 1em 0; } pre { margin: 0; } <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script> • Why (\\W+|^) not (\\W|^) – l4m2 Dec 14, 2017 at 14:42 ## Lua, 71 67 Bytes Woohoo, Lua isn't the longest solution! Still one byte behind python, but don't know how to golf this down. Indexes are 1-based. Thanks to @LeakyNun reminding me the existence of string.match, saved 4 bytes g,h=...print(g:sub(1,h):match"[%a_]*"..g:sub(h+1):match("[%a_]+"))


### Old 71

Note: the explanations are still based on this one, because it also applies to the new one, but contains some extra informations on gmatch

g,h=...print(g:sub(1,h):gmatch"[%a_]*$"()..g:sub(h+1):gmatch"[%a_]*"())  ### Explanation First, we unpack the arguments into g and h because they are shorter than arg[x] g,h=...  Then, we construct our output, which is the concatanation of the part before the cursor and after it. The first part of the string is g:sub(1,h)  We want to find the word at the end of this one, so we use the function string.gmatch :gmatch"[%a_]*$"


This pattern match 0..n times the character set of alphabet+underscore at the end of the string. gmatch returns an iterator on its list of match in the form of a function (using the principle of closure), so we execute it once to get the first part of our word

g:sub(1,h):gmatch"[%a_]*$"()  We get the second part of our word by the same way g:sub(h+1):gmatch"[%a_]*"())  The only difference being we don't have to specify we want to match at the start of the string (using [^%a_]*), as it will be the match returned by the iterator when it's called the first time. • g:sub(h+1):match"^[%a_]*"? Jul 19, 2016 at 7:50 • @LeakyNun totally forgot the existence of match \o/ saves lot of bytes, thanks Jul 19, 2016 at 7:52 • Jul 19, 2016 at 7:57 • I don't care, still -1 for "indexes". Jul 19, 2016 at 8:01 • Why don't we need the ^ anchor? Jul 19, 2016 at 8:02 # JavaScript (ES 6), 4342 Bytes s=>n=>s.replace(/\w*/g,(x,y)=>y<n?s=x:0)&&s  # JavaScript (ES 3), 65 Bytes function(s,n){s.replace(/\w*/g,function(x,y){y<n?s=x:0});alert(s)}  # 05AB1E, 14 bytes ð«._DžjмS¡Á2£J  Port of @AndersKaseorg's Pyth answer. 1-indexed like the challenge test cases. Explanation: ð« # Append a space to the (implicit) input-String ._ # Rotate this string the (implicit) input-integer amount of times # towards the left D # Duplicate this string žjм # Remove [a-zA-Z0-9_] from the string S¡ # Split the rotated string by each of the remaining characters Á # Rotate the resulting list once towards the right 2£J # And only leave the first two items, joined together # (which is output implicitly)  # Perl 6, 34 bytes ->\b{&{first *.to>b,m:g/<<\w+>>/}}  Try it online! Anonymous codeblock that takes input curried, like f(n)(string). ### Explanation: ->\b{ } # Anonymous code block that takes a number &{ } # And returns another code block that first ,m:g/<<\w+>>/ # Finds the first word in the input *.to>b # Where the start is after the number  # Ruby, 30 bytes ->s,n{s[/.{#{n}}\w+/][/\w+$/]}


Try it online!

A different approach, only 1 byte shorter and 3 years later. Why not?

# APL(NARS), 58 chars, 116 bytes

{m←⎕A,⎕a,⎕D,'_'⋄↑v⊂⍨m∊⍨v←⍵↓⍨¯1+⍵{⍵≤1:⍵⋄m∊⍨⍵⊃⍺:⍺∇⍵-1⋄⍵+1}⍺}


⍵{⍵≤1:⍵⋄m∊⍨⍵⊃⍺:⍺∇⍵-1⋄⍵+1}⍺ find where start the string...How to use and test:

  f←{m←⎕A,⎕a,⎕D,'_'⋄↑v⊂⍨m∊⍨v←⍵↓⍨¯1+⍵{⍵≤1:⍵⋄m∊⍨⍵⊃⍺:⍺∇⍵-1⋄⍵+1}⍺}
2 f 'abc def'
abc
5 f 'abc def'
def
2 f 'abc abc'
abc
4 f 'ab cd ef'
cd
1 f 'ab!cd'
ab
6 f 'ab   cd'
cd


# Jelly, 12 bytes

Żṙe€ØW¬œpƊ.ị


Try it online!

Port of Anders Kaseorg's Pyth answer.

Ż               Prepend a zero as a buffer between the first and last words,
ṙ              then rotate left by the index.
œpƊ      Partition that result around
€  ¬         elements which are not
e ØW          word characters,
.ị    then take the last and first slices
and smash-print them together.


Original:

# Jelly, 14 bytes

xðe€ØW¬Ä÷Ɗ=ị@¥


Try it online!

  e€ØW            For each element, is it a word character?
Ä          Take the cumulative sum
¬           of the negations
÷Ɗ        and divide by the original Booleans.
=       For each value in the result, is it equal to
ị@¥    the one at the index?
xð                Filter the string to truthy positions.


# MATL, 16 15 bytes

'\w+'5B#XXi>)1)


Cursor is 1-indexed and after the character (as in the test cases).

'\w+'    % Push string to be used as regex pattern
5B#XX    % Take input string implicitly. Apply regex. Push matches and ending indices
i>       % Take input number. Compare with obtained ending indices. Gives true for
% ending indices that exceed the input number
)        % Use as logical index to select the corresponding matches
1)       % Select the first match. Implicitly display


## PowerShell v3+, 103 101 bytes

param($a,$n)for(;$n[++$a]-match'\w'){}$i=$a--;for(;$n[--$a]-match'\w'-and$a-ge0){}-join$n[++$a..--$i]


Kind of a goofy solution, but a different approach than others.

Takes input $a as the 0-based index of the string $n. Then, we find the boundaries of our word. While we've not reached the end of the string and/or we're still matching word-characters, we ++$a. Then, because of fenceposting, we set $i=$a--. Next, we crawl backwards, decrementing $a until it's either 0 or we hit a non-word-character. We then slice the input string based on those two demarcations (with some increment/decrements to account for OBOE), and -join it together to produce the result.

### Examples

PS C:\Tools\Scripts\golfing> .\select-the-word-around-the-index.ps1 2 'This!test'
This

PS C:\Tools\Scripts\golfing> .\select-the-word-around-the-index.ps1 5 'This!test'
test

• select-the-word-around-the-index.ps1 Jul 19, 2016 at 17:06

# PHP, 98 bytes

function f($s,$p){foreach(preg_split('#\W+#',$s,-1,4)as$m)if($m[1]+strlen($m[0])>=$p)return$m[0];}

• splits the string by non-word-characters, remembering their position (4 == PREG_SPLIT_OFFSET_CAPTURE), loops through the words until position is reached.
• PHP strings are 0-indexed, cursor before character, but may be before or after the word

## Python 3, 112 140 bytes

from string import*
p='_'+printable[:62]
def f(s,h,r=''):
while s[h]in p and h>-1:h-=1
while h+1<len(s)and s[h]in p:h+=1;r+=s[h]
return r


0-indexed.

Seeks backward to the first alphanumeric character from the index, then goes forward to the last alphanumeric character after the index. There's probably a smarter way to do this.

Try it

• @LeakyNun _ was added, I'm not sure why I'd get an error for f('abc',1) though. Jul 19, 2016 at 13:30

## Javascript (using external library) (168 bytes)

(n,w)=> _.From(w).Select((x,i)=>({i:i,x:x})).Split((i,v)=>v.x==" ").Where(a=>a.Min(i=>i.i)<=n-1&&a.Max(i=>i.i)>=n-2).First().Select(i=>i.x).Write("").match(/^\w*^\w*/)[0]


Explanation of code: Library accepts a string, which gets parsed into a char array. It gets mapped to an object storing the index and the char. The sequence is split into subsequences at every occurrence of " ". The subsequences are filtered by checking if the cursor index is contained within the min and max index of the subsequence. Then we take the first subsequence. Then we transform back to just a char array. Then we concatenate all characters with "" as the delimiter. Then we validate against word regex. Then we take the first match.

• The word "word" is defined by the regex (?<!\w)\w+(?!\w), where \w is defined by [abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_], or "alphanumeric characters in ASCII including underscore". Jul 19, 2016 at 16:06
• When I run that regex against ab!cd on regex101.com I get this: No match groups were extracted. This means that your pattern matches but there were no (capturing (groups)) in it that matched anything in the subject string. Maybe I'm making a mistake somewhere... Jul 19, 2016 at 16:10
• Why would I need to capture anything? Jul 19, 2016 at 16:15
• I know this isnt the place to learn, but I'm saying that when I run that regex against ab!cd I don't get anything. So why would 'ab' be the correct output? Jul 19, 2016 at 16:20
• You are invited to our chatroom to further discuss your answer. Jul 19, 2016 at 16:22