Selecione a palavra ao redor do índice especificado em uma determinada sequência

20

No Windows, quando você clica duas vezes em um texto, a palavra ao redor do cursor no texto será selecionada.

(Esse recurso tem propriedades mais complicadas, mas não será necessário implementá-lo para esse desafio.)

Por exemplo, deixe |seu cursor entrar abc de|f ghi.

Então, quando você clicar duas vezes, a substring defserá selecionada.

Entrada / Saída

Você receberá duas entradas: uma sequência e um número inteiro.

Sua tarefa é retornar a palavra-substring da string em torno do índice especificado pelo número inteiro.

Seu cursor pode estar logo antes ou logo após o caractere na sequência no índice especificado.

Se você usar logo antes , especifique na sua resposta.

Especificações (Especificações)

É garantido que o índice esteja dentro de uma palavra, portanto, não há casos extremos como abc |def ghiou abc def| ghi.

A sequência conterá apenas caracteres ASCII imprimíveis (de U + 0020 a U + 007E).

A palavra "palavra" é definida pelo regex (?<!\w)\w+(?!\w), onde \wé definido por [abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_], ou "caracteres alfanuméricos em ASCII, incluindo sublinhado".

O índice pode ser indexado 1 ou 0.

Se você usa o índice 0, especifique-o na sua resposta.

Casos de teste

As caixas de teste são indexadas em 1 e o cursor fica logo após o índice especificado.

A posição do cursor é apenas para fins de demonstração, que não precisará ser emitida.

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
Freira Furada
fonte
2
A sequência pode conter novas linhas?
Ou orp
@orlp O desafio foi editado para restringir a entrada ao ASCII imprimível, para que a entrada não contenha novas linhas.
FryAmTheEggman
Suas caixas de teste não contêm outros delimitadores além de espaços. Que tal uma palavra como we're?
orlp 18/07/19
2
O que deve "ab...cd", 3retornar?
Titus
5
@Titus "É garantido que o índice esteja dentro de uma palavra"
Martin Ender

Respostas:

10

V , 10, 9 7 bytes

À|diwVp

Experimente online!

Esta resposta usa indexação baseada em 1.

Isso pode ser menor se fizermos exatamente o que o título diz: " Selecione a palavra ao redor do índice especificado em uma string". Nós poderíamos fazer

À|viw

Que literalmente seleciona a palavra, mas infelizmente não altera a saída. Portanto, precisamos de uma solução alternativa para fazê-lo funcionar, cortando-o em um registro, excluindo o restante do texto e colando o registro novamente.

Explicação:

À|          " 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
DJMcMayhem
fonte
5

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

Espera que a entrada no stdin seja o índice baseado em 0 seguido por um espaço ou nova linha, seguido pela sequência. O comprimento máximo de uma palavra é de 99 caracteres. Por exemplo:

2 abc def
orlp
fonte
É muito legal ver C e perl empatados em um desafio baseado em strings. :D
DJMcMayhem
A sequência de entrada pode ter mais de 100 caracteres?
Freira vazando
@LeakyNun Sim, mas uma palavra não pode ter mais de 100 caracteres.
orlp 18/07/19
Você deseja colocar esse requisito em sua resposta?
Leaky Nun
@DrGreenEggsandIronMan Pena que eu tive que corrigir minha resposta porque ela estava delimitada em branco :(
orlp
4

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

Indexado a zero, define uma função que aceita o índice e depois a sequência.

orlp
fonte
Eu acho que isalnum(*++p)|*p==95é um comportamento indefinido.
Owacoder
@owacoder É, mas o que importa é que o gcc cospe um executável que funcione. *++p^95?isalnum(*p):1é um byte mais longo, mas funciona em todos os compiladores.
Ou orp
Presumo que o espaço principal seja um erro de digitação? Além disso, aqui está um link IDEone preguiçoso.
FryAmTheEggman
isalnum(*++p)||*p==95também funciona, para um byte adicionado.
Owacoder
@FryAmTheEggman Sim, foi corrigido agora.
Ou orp
3

Retina, 22

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

Experimente online! ou verifique todos os casos de teste . O programa regular assume a posição do cursor em unário, seguido por uma nova linha e depois pela string. O conjunto de testes possui código adicional para executar no modo por linha e usa a \como delimitador e decimal, por conveniência.

Usa grupos de balanceamento para encontrar a posição do cursor e depois recua até um limite de palavras. Exclui o texto até a palavra e depois da palavra.

FryAmTheEggman
fonte
2

C, 115 bytes

A função f()requer a string e o índice (indexados 1) como parâmetros e imprime o resultado em stdout. O cursor deve estar após o caractere especificado.

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

JavaScript (ES6), 57 bytes

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

Simplesmente fatie a sequência no ponto do cursor (que está antes do caractere indexado 0, que funciona da mesma forma que o caractere indexado 1), depois extrai e concatena os fragmentos de palavras adjacentes. Even retorna um resultado sensível quando o cursor está no início, no final ou em nenhum lugar perto de uma palavra.

Neil
fonte
Você precisa do * no último regex?
115516 Charlie Wynn
@CharlieWynn Sim, caso contrário, o segundo caso de teste retornaria apenas de.
Neil
whoops, demos azar com os testes Corri
Charlie Wynn
2

Java 8, 86 78 bytes

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

Sem jogar com casos de teste:

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

Divide a sequência por caracteres não alfanuméricos e continua subtraindo o comprimento de cada substring, mais 1, da posição especificada, até que se torne negativo. Como qualquer não alfanumérico repetido é representado como uma sequência vazia, a lógica de subtração é significativamente mais fácil.

Esse código não é extensivamente testado, então eu gostaria de ver se alguém pode quebrar isso. Além disso, considerando que esse é o código Java, como essa não é a resposta mais longa aqui? : P


fonte
Eu sei que já faz quase três anos, mas (s,p)->pode ser s->p->usando uma expressão lambda de curry (ie java.util.function.Function<String, java.util.function.Function<String, String>> f). Além disso, Stringpoderia ser varagora se alternado para o Java 10, embora isso não estivesse disponível no momento. Independentemente, boa resposta. Vejo que já o atualizei em algum lugar no passado. :)
Kevin Cruijssen 15/03
2

Pitão, 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

Experimente online

Anders Kaseorg
fonte
2

Pyke, 19 bytes

#Q;cjmli<i+s)lttjR@

Experimente aqui!

Utiliza-se Q;como não operacional para garantir que a primeira entrada seja colocada corretamente

#          )   -  first where
   c           -       input.split()
    ml         -      map(len, ^)
      i<       -     ^[:i]
        i+     -    ^+[i]
          s    -   sum(^)
            lt - len(^)-2
Azul
fonte
Estou tendo um erro 504 quando clico no seu link.
Leaky Nun
@LeakyNun Sim, eu matei-o por acidente enquanto escrita que é por isso que eu tinha no link localhost, ele vai voltar
Azul
1
Seu programa parece ser a saída N onde a palavra Nth é o selecionado, mas precisamos da palavra completa
Valor de tinta
2

Python 2, 70 66 bytes

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

Divide a sequência por separadores que não são palavras, uma vez na sequência original até o índice do cursor e depois na sequência iniciada no índice do cursor. Retorna o último elemento da divisão esquerda mais o primeiro elemento da divisão direita. Agradecimentos a Leaky Nun por salvar 4 bytes!

Cowabunghole
fonte
1

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

Primeiro, divide a string de entrada na posição kem duas strings. Em seguida, para essas cadeias, encontre ocorrências "\w+"e retorne-as como lista. Em seguida, concatene o último elemento da primeira lista e o primeiro elemento da segunda lista.

Veja on-line: https://ideone.com/Dk2FIs

cliffroot
fonte
1

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>

George Reith
fonte
Por que (\\W+|^)não(\\W|^)
L4m2
1

Lua, 71 67 Bytes

Woohoo, Lua não é a solução mais longa! Ainda um byte por trás do python, mas não sei como resolver isso. Os índices são baseados em 1.

Graças a @LeakyNun me lembrando a existência de string.match, salvou 4 bytes

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

Antigo 71

Nota: as explicações ainda se baseiam nesta, porque também se aplica à nova, mas contém algumas informações extras sobre gmatch

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

Explicação

Primeiro, descompactamos os argumentos em ge hporque são mais curtos do quearg[x]

g,h=...

Em seguida, construímos nossa saída, que é a concatanação da peça antes e depois do cursor.

A primeira parte da string é

g:sub(1,h)

Queremos encontrar a palavra no final deste, então usamos a função string.gmatch

:gmatch"[%a_]*$"

Essa correspondência de padrão 0..nvezes o conjunto de caracteres do alfabeto + sublinhado no final da sequência. gmatchretorna um iterador em sua lista de correspondências na forma de uma função (usando o princípio de fechamento); portanto, executamos uma vez para obter a primeira parte da nossa palavra

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

Recebemos a segunda parte da nossa palavra da mesma maneira

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

A única diferença é que não precisamos especificar que queremos corresponder no início da string (using [^%a_]*), pois será a correspondência retornada pelo iterador quando for chamada pela primeira vez.

Katenkyo
fonte
g:sub(h+1):match"^[%a_]*"?
Freira vazando
@LeakyNun esqueceu totalmente a existência de match\ o / poupa muito bytes, graças
Katenkyo
-1 para "índices"
Leaky Nun
Eu não ligo, ainda -1 para "índices".
Freira vazando
1

Javascript (usando biblioteca externa) (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]

Link para lib: https://github.com/mvegh1/Enumerable/blob/master/linq.js

Explicação do código: Library aceita uma string, que é analisada em uma matriz char. Ele é mapeado para um objeto que armazena o índice e o caractere. A sequência é dividida em subsequências a cada ocorrência de "". As subsequências são filtradas, verificando se o índice do cursor está contido nos índices mínimo e máximo da subsequência. Então tomamos a primeira subsequência. Depois, transformamos novamente em apenas uma matriz de caracteres. Em seguida, concatenamos todos os caracteres com "" como delimitador. Em seguida, validamos com a palavra regex. Então vamos dar a primeira partida.

insira a descrição da imagem aqui

applejacks01
fonte
A palavra "palavra" é definida pelo regex (?<!\w)\w+(?!\w), onde \wé definido por [abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_], ou "caracteres alfanuméricos em ASCII, incluindo sublinhado".
gotejante Nun
Quando executo esse regex contra o ab! Cd no regex101.com, recebo o seguinte: Nenhum grupo de correspondência foi extraído. Isso significa que seu padrão corresponde, mas não havia (captura (grupos)) nele que correspondia a qualquer coisa na sequência de assunto. Talvez eu estou fazendo um algum lugar erro ...
applejacks01
Por que eu precisaria capturar alguma coisa?
Freira vazando
Sei que este não é o lugar para aprender, mas estou dizendo que, quando executo esse regex no ab! Cd, não recebo nada. Então, por que 'ab' seria a saída correta?
applejacks01
1

Perl 6 , 34 bytes

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

Experimente online!

Codeblock anônimo que recebe entrada com curry, como f(n)(string).

Explicação:

->\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
Brincadeira
fonte
1

Ruby , 30 bytes

->s,n{s[/.{#{n}}\w+/][/\w+$/]}

Experimente online!

Uma abordagem diferente, apenas 1 byte mais curto e 3 anos depois. Por que não?

GB
fonte
1

APL (NARS), 58 caracteres, 116 bytes

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

⍵ {⍵≤1: ⍵⋄m∊⍨⍵⊃⍺: ⍺∇⍵-1⋄⍵ + 1} ⍺ encontre onde iniciar a string ... Como usar e testar:

  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 
RosLuP
fonte
0

MATL , 16 15 bytes

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

O cursor é indexado em 1 e após o caractere (como nos casos de teste).

Experimente online! Ou verifique todos os casos de teste .

'\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
Luis Mendo
fonte
0

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]

Uma espécie de solução pateta, mas com uma abordagem diferente das outras.

Recebe a entrada $acomo o índice baseado em 0 da sequência $n. Então, encontramos os limites da nossa palavra. Enquanto não chegamos ao final da string e / ou ainda estamos combinando caracteres de palavra, nós ++$a. Então, por causa da colocação de cerca, nós montamos $i=$a--. Em seguida, rastreamos para trás, decrementando $aaté que seja um 0ou atingimos um caractere que não seja palavra. Em seguida, dividimos a sequência de entrada com base nessas duas demarcações (com alguns incrementos / decréscimos para contabilizar o OBOE), e -joinjuntas para produzir o resultado.

Exemplos

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
AdmBorkBork
fonte
select-the-word-around-the-index.ps1
Leaky Nun
0

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];}
  • divide a cadeia de caracteres por caracteres que não sejam palavras, lembrando-se de sua posição ( 4== PREG_SPLIT_OFFSET_CAPTURE), percorre as palavras até que a posição seja atingida.
  • As strings do PHP são indexadas em 0, cursor antes do caractere, mas podem estar antes ou depois da palavra
Titus
fonte
0

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

Indexado a 0.

Procura de volta para o primeiro caractere alfanumérico do índice e depois avança para o último caractere alfanumérico após o índice. Provavelmente existe uma maneira mais inteligente de fazer isso.

Tente

atlasologist
fonte
@LeakyNun _foi adicionado, mas não sei por que receberia um erro f('abc',1).
Atlasologist
0

JavaScript (ES 6), 43 42 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)}
l4m2
fonte
0

05AB1E , 14 bytes

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

Porto de @AndersKaseorg é resposta Pyth .

1 indexado como os casos de teste de desafio.

Experimente online ou verifique todos os casos de teste .

Explicação:

ð«              # 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)
Kevin Cruijssen
fonte