Выберите слово вокруг данного индекса в данной строке


20

В Windows при двойном щелчке по тексту будет выделено слово вокруг курсора в тексте.

(Эта функция имеет более сложные свойства, но их не нужно будет реализовывать для этой задачи.)

Например, пусть |ваш курсор в abc de|f ghi.

Затем при двойном щелчке defбудет выбрана подстрока .

Ввод, вывод

Вам будет дано два ввода: строка и целое число.

Ваша задача - вернуть слово-подстроку строки вокруг индекса, указанного целым числом.

Ваш курсор может находиться прямо перед или сразу после символа в строке с указанным индексом.

Если вы используете прямо раньше , пожалуйста, укажите в своем ответе.

Технические характеристики (спецификации)

Индекс гарантированно находится внутри слова, поэтому никакие крайние случаи, такие как abc |def ghiили abc def| ghi.

Строка будет содержать только печатные символы ASCII (от U + 0020 до U + 007E).

Слово «слово» определяется регулярным выражением (?<!\w)\w+(?!\w), где \wоно определяется [abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_]или «буквенно-цифровыми символами в ASCII, включая подчеркивание».

Индекс может быть 1-индексирован или 0-индексирован.

Если вы используете 0-индексированный, укажите это в своем ответе.

Testcases

Тестовые случаи 1-индексированы, и курсор находится сразу после указанного индекса.

Положение курсора только для демонстрационных целей, которые не требуется выводить.

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

2
Может ли строка содержать символы новой строки?
orlp

@orlp Задача была отредактирована, чтобы ограничить ввод для печати ASCII, чтобы ввод не содержал новых строк.
FryAmTheEggman

Ваши тестовые случаи не содержат никаких других разделителей, кроме пробелов. Как насчет слова, как we're?
orlp

2
Что должно "ab...cd", 3вернуться?
Тит

5
@Titus «Индекс гарантированно находится внутри слова»
Мартин Эндер,

Ответы:


10

V , 10, 9 7 байт

À|diwVp

Попробуйте онлайн!

Этот ответ использует индексирование на основе 1.

Это может быть короче, если мы сделаем именно то, что написано в заголовке: « Выберите слово вокруг заданного индекса в строке». Мы могли бы сделать

À|viw

Который буквально выбирает слово, но, к сожалению, не меняет вывод вообще. Поэтому нам нужно немного обойти это, чтобы он работал, вырезав его в регистр, удалив остальную часть текста, а затем вставив регистр обратно.

Объяснение:

À|          " 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

5

C 104 байта

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);}

Ожидается, что вводом в stdin будет индекс, основанный на 0, за которым следуют один пробел или символ новой строки, за которым следует строка. Максимальная длина слова составляет 99 символов. Например:

2 abc def

Это действительно круто видеть C и Perl, связанный с вызовом на основе строки. :D
DJMcMayhem

Может ли входная строка содержать более 100 символов?
Утренняя монахиня

@LeakyNun Да, но одно слово не может быть длиннее 100 символов.
orlp

Вы хотите вставить это требование в свой ответ?
Утренняя монахиня

@DrGreenEggsandIronMan Очень жаль, что мне пришлось исправить свой ответ, потому что он был разделен
пробелами

4

C (gcc), 94 байта

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

Индексируется нулями, определяет функцию, которая берет индекс, затем строку.


Я думаю, что isalnum(*++p)|*p==95неопределенное поведение.
owacoder

@owacoder Да, но важно то, что gcc выдает исполняемый файл, который работает. *++p^95?isalnum(*p):1на один байт длиннее, но работает на каждом компиляторе.
orlp

Я полагаю, ведущее место опечатка? Кроме того, вот ленивая ссылка IDEone.
FryAmTheEggman

isalnum(*++p)||*p==95также работает, для добавленного одного байта.
owacoder

@FryAmTheEggman Да, исправлено.
orlp

3

Сетчатка, 22

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

Попробуйте онлайн! или проверьте все контрольные примеры . Обычная программа занимает позицию курсора в унарном виде, за которой следует новая строка, а затем строка. В тестовом наборе есть дополнительный код для запуска в построчном режиме, \в качестве разделителя используется a, а для удобства используется десятичный.

Использует группы балансировки, чтобы найти позицию курсора, а затем возвращается к границе слова. Удаляет текст до слова, а затем после слова.


2

C, 115 байтов

Функция f()требует строку и индекс (1-indexed) в качестве параметров и выводит результат в стандартный вывод. Курсор должен быть после указанного символа.

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++));}

2

JavaScript (ES6), 57 байт

f=(s,n)=>s.slice(0,n).match(/\w*$/)+s.slice(n).match(/\w*/)

Просто нарезает строку в точке курсора (которая находится перед 0-индексированным символом, который работает так же, как после 1-индексированного символа), затем извлекает и объединяет соседние фрагменты слова. Даже возвращает разумный результат, когда курсор находится в начале, конце или рядом с словом.


Вам нужен * в последнем регулярном выражении?
Чарли Винн

@CharlieWynn Да, в противном случае второй тестовый случай будет только возвращаться de.
Нил

Ой, повезло с тестами, которые я провел
Чарли Уинн

2

Java 8, 86 78 байт

(s,p)->{for(String t:s.split("\\W"))if((p-=t.length()+1)<0)return t;return"";}

Разоблачен тестовыми примерами:

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));
    }
}

Разбивает строку не буквенно-цифровыми символами, затем продолжает вычитать длину каждой подстроки плюс 1 из указанной позиции, пока она не станет отрицательной. Поскольку любые повторяющиеся не алфавитно-цифровые символы представляются в виде пустой строки, логика вычитания значительно упрощается.

Этот код не был тщательно протестирован, поэтому я хотел бы посмотреть, сможет ли кто-нибудь это сломать. Кроме того, учитывая, что это код Java, как это не самый длинный ответ здесь? :П


Я знаю, что это было почти три года, но (s,p)->может быть s->p->с помощью карри лямбда-выражения (то есть java.util.function.Function<String, java.util.function.Function<String, String>> f). Кроме того, Stringможет быть varсейчас, если переключиться на Java 10, хотя это было недоступно в то время, конечно. Независимо, хороший ответ. Я вижу, я уже обновил его где-то в прошлом. :)
Кевин Круйссен



2

Пайк, 19 байт

#Q;cjmli<i+s)lttjR@

Попробуй это здесь!

Используется Q;как неактивный, чтобы убедиться, что первый вход размещен правильно

#          )   -  first where
   c           -       input.split()
    ml         -      map(len, ^)
      i<       -     ^[:i]
        i+     -    ^+[i]
          s    -   sum(^)
            lt - len(^)-2

У меня ошибка 504 при нажатии на вашу ссылку.
Утренняя монахиня

@LeakyNun Да, я убил его случайно, пока писал, поэтому у меня была ссылка на локальный сервер, она вернется
Blue


1
Похоже, ваша программа выводит N, где выбрано N-е слово, но нам нужно полное слово
Value Ink

2

Python 2, 70 66 байт

import re
f=lambda x,y,r=re.split:r('\W',x[:y])[-1]+r('\W',x[y:])[0]

Разбивает строку на разделители без слов: один раз на исходную строку до индекса курсора, затем на строку, начинающуюся с индекса курсора. Возвращает последний элемент разделения слева и первый элемент разделения справа. Спасибо Leaky Nun за сохранение 4 байта!


1

Clojure, 92 байта

(fn[x k](let[[u i](map #(re-seq #"\w+"(apply str %))(split-at k x))](str(last u)(nth i 0))))

Сначала разбивает входную строку в позиции kна две строки. Затем для этих строк найдите вхождения "\w+"и верните их в виде списка. Затем объедините последний элемент первого списка и первый элемент второго списка.

Смотрите это онлайн: https://ideone.com/Dk2FIs


1

JavaScript (ES6), 52 байта

(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>


Почему бы и (\\W+|^)нет(\\W|^)
14м2,

1

Луа, 71 67 байт

Woohoo, Lua не самое длинное решение! Еще один байт позади питона, но я не знаю, как это сделать. Индексы основаны на 1.

Благодаря @LeakyNun, напоминающему мне о существовании string.match, сэкономлено 4 байта

g,h=...print(g:sub(1,h):match"[%a_]*$"..g:sub(h+1):match("[%a_]+"))

Старый 71

Примечание: объяснения все еще основаны на этом, потому что это также относится к новому, но содержит некоторую дополнительную информацию о gmatch

g,h=...print(g:sub(1,h):gmatch"[%a_]*$"()..g:sub(h+1):gmatch"[%a_]*"())

объяснение

Сначала мы распаковываем аргументы в gи hпотому что они корочеarg[x]

g,h=...

Затем мы создаем наш вывод, который является конкатенацией части перед курсором и после него.

Первая часть строки

g:sub(1,h)

Мы хотим найти слово в конце этого, поэтому мы используем функцию string.gmatch

:gmatch"[%a_]*$"

Этот шаблон соответствует 0..nвремени набора символов алфавита + подчеркивания в конце строки. gmatchвозвращает итератор в своем списке совпадений в виде функции (используя принцип замыкания), поэтому мы выполняем его один раз, чтобы получить первую часть нашего слова

g:sub(1,h):gmatch"[%a_]*$"()

Мы получаем вторую часть нашего слова таким же образом

g:sub(h+1):gmatch"[%a_]*"())

Единственное отличие заключается в том, что нам не нужно указывать, что мы хотим сопоставить в начале строки (используя [^%a_]*), поскольку это будет совпадение, возвращаемое итератором при первом вызове.


g:sub(h+1):match"^[%a_]*"?
Дрянная Монахиня

@LeakyNun полностью забыл, что match\ o / экономит много байтов, спасибо
Katenkyo

-1 для "индексов"
Лики Монахиня


Мне все равно, все еще -1 для "индексов".
Дрянная Монахиня

1

Javascript (с использованием внешней библиотеки) (168 байт)

(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]

Ссылка на lib: https://github.com/mvegh1/Enumerable/blob/master/linq.js

Объяснение кода: Библиотека принимает строку, которая разбирается в массив символов. Он сопоставляется с объектом, хранящим индекс и символ. Последовательность разбивается на подпоследовательности при каждом появлении "". Подпоследовательности фильтруются путем проверки того, содержится ли указатель курсора в указателе min и max подпоследовательности. Затем мы берем первую подпоследовательность. Затем мы преобразуем обратно в просто массив символов. Затем мы объединяем все символы с "" в качестве разделителя. Затем мы проверяем слово regex. Тогда мы берем первый матч.

введите описание изображения здесь


Слово «слово» определяется регулярным выражением (?<!\w)\w+(?!\w), где \wоно определяется [abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_]или «буквенно-цифровыми символами в ASCII, включая подчеркивание».
Дрянная Монахиня

Когда я запускаю это регулярное выражение против ab! Cd на regex101.com, я получаю следующее: группы совпадений не были извлечены. Это означает, что ваш шаблон соответствует, но в нем не было (захвата (групп)), которые соответствовали бы чему-либо в строке темы. Может я где-то ошибаюсь ...
applejacks01

Зачем мне нужно что-то захватывать?
Утренняя монахиня

Я знаю, что это не то место, где нужно учиться, но я говорю, что когда я запускаю это регулярное выражение против ab! Cd, я ничего не получаю. Так почему же «ab» будет правильным выводом?
applejacks01


1

Perl 6 , 34 байта

->\b{&{first *.to>b,m:g/<<\w+>>/}}

Попробуйте онлайн!

Анонимный кодовый блок, который принимает ввод карри, как f(n)(string).

Объяснение:

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


1

APL (NARS), 58 символов, 116 байтов

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

⍵ {⍵≤1: ⍵⋄m∊⍨⍵⊃⍺: ⍺∇⍵-1⋄⍵ + 1} ⍺ найти начало строки ... Как использовать и тестировать:

  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 

0

MATL , 16 15 байт

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

Курсор индексируется 1 и после символа (как в тестовых примерах).

Попробуйте онлайн! Или проверьте все тестовые случаи .

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

0

PowerShell v3 +, 103 101 байт

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

Вид глупого решения, но другой подход, чем другие.

Принимает ввод $aкак нулевой индекс строки $n. Затем мы находим границы нашего слова. Пока мы не достигли конца строки и / или мы все еще сопоставляем слова-символы, мы ++$a. Затем из-за забора мы устанавливаем $i=$a--. Затем мы ползем назад, уменьшаясь, $aпока не будет0 мы не столкнемся с несловесным символом. Затем мы нарезаем входную строку на основе этих двух разграничений (с некоторыми приращениями / уменьшениями для учета OBOE), и -joinэто вместе для получения результата.

Примеры

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
Дрянная Монахиня

0

PHP, 98 байт

function f($s,$p){foreach(preg_split('#\W+#',$s,-1,4)as$m)if($m[1]+strlen($m[0])>=$p)return$m[0];}
  • разбивает строку не-словесными символами, запоминая их положение ( 4== PREG_SPLIT_OFFSET_CAPTURE), циклически перебирает слова, пока не будет достигнута позиция.
  • Строки PHP имеют индекс 0, курсор перед символом, но может быть до или после слова

0

Python 3, 112 140 байт

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 индексированные.

Поиск назад к первому буквенно-цифровому символу из индекса, а затем переход к последнему буквенно-цифровому символу после индекса. Вероятно, есть более разумный способ сделать это.

Попытайся


@LeakyNun _был добавлен, я не уверен, почему я получил ошибку, f('abc',1)хотя.
атласолог

0

JavaScript (ES 6), 43 42 байта

s=>n=>s.replace(/\w*/g,(x,y)=>y<n?s=x:0)&&s

JavaScript (ES 3), 65 байт

function(s,n){s.replace(/\w*/g,function(x,y){y<n?s=x:0});alert(s)}

0

05AB1E , 14 байтов

ð«._DžjмS¡Á2£J

Порт @AndersKaseorg 's Pyth answer .

1-индексируется как контрольные тесты.

Попробуйте онлайн или проверьте все контрольные примеры .

Объяснение:

ð«              # 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)
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.