Seleccione la palabra alrededor del índice dado en una cadena dada

20

En Windows, cuando realiza doble clic en un texto, se seleccionará la palabra alrededor del cursor en el texto.

(Esta característica tiene propiedades más complicadas, pero no será necesario implementarlas para este desafío).

Por ejemplo, deje |que su cursor entre abc de|f ghi.

Luego, cuando haga doble clic, defse seleccionará la subcadena .

De entrada y salida

Se le darán dos entradas: una cadena y un número entero.

Su tarea es devolver la subcadena de palabras de la cadena alrededor del índice especificado por el entero.

Su cursor puede estar justo antes o justo después del carácter en la cadena en el índice especificado.

Si usa antes , especifique en su respuesta.

Especificaciones (especificaciones)

El índice está garantizado para estar dentro de una palabra, por lo que no hay casos extremos como abc |def ghio abc def| ghi.

La cadena solo contendrá caracteres ASCII imprimibles (de U + 0020 a U + 007E).

La palabra "palabra" está definida por la expresión regular (?<!\w)\w+(?!\w), donde \westá definida por [abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_], o "caracteres alfanuméricos en ASCII incluyendo el guión bajo".

El índice puede ser 1 indexado o 0 indexado.

Si utiliza 0 indexado, especifíquelo en su respuesta.

Casos de prueba

Los casos de prueba están indexados en 1 y el cursor está justo después del índice especificado.

La posición del cursor es solo para fines de demostración, que no se requerirá que salga.

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
Monja permeable
fuente
2
¿Puede la cadena contener nuevas líneas?
orlp
@orlp El desafío se editó para restringir la entrada a ASCII imprimible para que la entrada no contenga nuevas líneas.
FryAmTheEggman
Sus casos de prueba no contienen otros delimitadores que no sean espacios. ¿Qué tal una palabra como we're?
orlp
2
¿Qué debería "ab...cd", 3volver?
Titus
55
@Titus "El índice está garantizado dentro de una palabra"
Martin Ender

Respuestas:

10

V , 10, 9 7 bytes

À|diwVp

Pruébalo en línea!

Esta respuesta utiliza indexación basada en 1.

Esto podría ser más corto si hacemos exactamente lo que dice el título: " Seleccione la palabra alrededor del índice dado en una cadena". Podríamos hacer

À|viw

Que literalmente selecciona la palabra, pero desafortunadamente no cambia la salida en absoluto. Por lo tanto, necesitamos una pequeña solución para hacerlo funcionar cortándolo en un registro, eliminando el resto del texto y luego pegando el registro nuevamente.

Explicación:

À|          " 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
fuente
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 la entrada en stdin sea el índice basado en 0 seguido de un espacio o nueva línea, seguido de la cadena. La longitud máxima de una palabra es de 99 caracteres. P.ej:

2 abc def
orlp
fuente
Es realmente genial ver a C y Perl atados en un desafío basado en cuerdas. :D
DJMcMayhem
¿Puede la cadena de entrada tener más de 100 caracteres?
Leaky Nun
@LeakyNun Sí, pero una palabra no puede tener más de 100 caracteres.
orlp
¿Te apetece poner ese requisito dentro de tu respuesta?
Leaky Nun
@DrGreenEggsandIronMan Lástima que tuve que arreglar mi respuesta porque estaba delimitada en espacios en blanco :(
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 cero, define una función que toma el índice, luego la cadena.

orlp
fuente
Creo que isalnum(*++p)|*p==95es un comportamiento indefinido.
owacoder
@owacoder Lo es, pero lo que importa es que gcc escupe un ejecutable que funciona. *++p^95?isalnum(*p):1es un byte más largo, pero funciona en todos los compiladores.
orlp
¿Asumo que el espacio inicial es un error tipográfico? Además, aquí hay un enlace perezoso de IDEone.
FryAmTheEggman
isalnum(*++p)||*p==95también funciona, por un byte adicional.
owacoder
@FryAmTheEggman Sí, está arreglado ahora.
orlp
3

Retina, 22

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

Pruébalo en línea! o verificar todos los casos de prueba . El programa regular toma la posición del cursor en unario seguido de una nueva línea y luego la cadena. El conjunto de pruebas tiene un código adicional para ejecutarse en modo por línea, y usa a \como delimitador, y usa decimal, por conveniencia.

Utiliza grupos de equilibrio para encontrar la posición del cursor, luego retrocede hasta un límite de palabra. Elimina el texto hasta la palabra y luego después de la palabra.

FryAmTheEggman
fuente
2

C, 115 bytes

La función f()requiere la cadena y el índice (1 indexado) como parámetros e imprime el resultado en stdout. El cursor debe estar después del carácter 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
fuente
2

JavaScript (ES6), 57 bytes

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

Simplemente corta la cadena en el punto del cursor (que está antes del carácter indexado 0, que funciona igual que después del carácter indexado 1), luego extrae y concatena los fragmentos de palabras adyacentes. Incluso devuelve un resultado sensible cuando el cursor está al principio, al final o en ninguna parte cerca de una palabra.

Neil
fuente
¿Necesitas el * en la última expresión regular?
Charlie Wynn
@CharlieWynn Sí, de lo contrario, el segundo caso de prueba solo regresaría de.
Neil
whoops, tuve mala suerte con las pruebas que realicé
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"";}

Sin golfos con casos de prueba:

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 la cadena por caracteres no alfanuméricos, luego resta la longitud de cada subcadena, más 1, de la posición especificada, hasta que se vuelve negativa. Dado que cualquier repetición no alfanumérica se representa como una cadena vacía, la lógica de resta es significativamente más fácil.

Este código no se ha probado exhaustivamente, por lo que me gustaría ver si alguien puede romper esto. Además, teniendo en cuenta que este es un código Java, ¿cómo es que esta no es la respuesta más larga aquí? :PAG


fuente
Sé que han pasado casi tres años, pero (s,p)->puede ser s->p->usando una expresión lambda al curry (es decir java.util.function.Function<String, java.util.function.Function<String, String>> f). Además, Stringpodría ser varahora si se cambia a Java 10, aunque eso no estaba disponible en el momento, por supuesto. De todos modos, buena respuesta. Veo que ya lo actualicé en algún lugar del pasado. :)
Kevin Cruijssen
2

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

Pruébalo en línea

Anders Kaseorg
fuente
2

Pyke, 19 bytes

#Q;cjmli<i+s)lttjR@

Pruébalo aquí!

Se utiliza Q;como no operativo para asegurarse de que la primera entrada se coloca correctamente

#          )   -  first where
   c           -       input.split()
    ml         -      map(len, ^)
      i<       -     ^[:i]
        i+     -    ^+[i]
          s    -   sum(^)
            lt - len(^)-2
Azul
fuente
Tengo un error 504 cuando hago clic en su enlace.
Leaky Nun
@LeakyNun Sí, lo maté por accidente mientras escribía, por eso tuve el enlace localhost, volverá
Azul
1
Su programa parece estar generando N donde la enésima palabra es la seleccionada, pero necesitamos la palabra completa
Value Ink el
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 la cadena por separadores que no son palabras, una vez en la cadena original hasta el índice del cursor, luego en la cadena que comienza en el índice del cursor. Devuelve el último elemento de la división izquierda más el primer elemento de la división derecha. ¡Gracias a Leaky Nun por guardar 4 bytes!

Agujero de vaca
fuente
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))))

Primero, divide la cadena de entrada en la posición ken dos cadenas. Luego, para estas cadenas, encuentre las ocurrencias de "\w+"y devuélvalas como una lista. Luego concatene el último elemento de la primera lista y el primer elemento de la segunda lista.

Véalo en línea: https://ideone.com/Dk2FIs

acantilado
fuente
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
fuente
¿Por qué (\\W+|^)no?(\\W|^)
l4m2
1

Lua, 71 67 bytes

Woohoo, ¡Lua no es la solución más larga! Todavía hay un byte detrás de Python, pero no sé cómo jugar golf. Los índices están basados ​​en 1.

Gracias a @LeakyNun recordándome la existencia de string.match4 bytes guardados

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

Viejo 71

Nota: las explicaciones todavía se basan en esta, porque también se aplica a la nueva, pero contiene información adicional sobre gmatch

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

Explicación

Primero, descomprimimos los argumentos en gy hporque son más cortos quearg[x]

g,h=...

Luego, construimos nuestra salida, que es la concatenación de la parte anterior al cursor y después de este.

La primera parte de la cadena es

g:sub(1,h)

Queremos encontrar la palabra al final de esta, así que usamos la función string.gmatch

:gmatch"[%a_]*$"

Esta coincidencia de patrón 0..nmultiplica por el conjunto de caracteres del alfabeto + guión bajo al final de la cadena. gmatchdevuelve un iterador en su lista de coincidencias en forma de función (utilizando el principio de cierre), por lo que lo ejecutamos una vez para obtener la primera parte de nuestra palabra

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

Obtenemos la segunda parte de nuestra palabra de la misma manera

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

La única diferencia es que no tenemos que especificar que queremos hacer coincidir al comienzo de la cadena (usando [^%a_]*), ya que será la coincidencia devuelta por el iterador cuando se llame por primera vez.

Katenkyo
fuente
g:sub(h+1):match"^[%a_]*"?
Leaky Nun
@LeakyNun olvidó por completo la existencia de match\ o / ahorra muchos bytes, gracias
Katenkyo
-1 para "índices"
Leaky Nun
No me importa, todavía -1 para "índices".
Leaky Nun
1

Javascript (usando una 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]

Enlace a lib: https://github.com/mvegh1/Enumerable/blob/master/linq.js

Explicación del código: la biblioteca acepta una cadena, que se analiza en una matriz de caracteres. Se asigna a un objeto que almacena el índice y el carácter. La secuencia se divide en subsecuencias en cada aparición de "". Las subsecuencias se filtran comprobando si el índice del cursor está contenido dentro del índice mínimo y máximo de la subsecuencia. Luego tomamos la primera subsecuencia. Luego nos transformamos de nuevo a solo una matriz de caracteres. Luego concatenamos todos los caracteres con "" como delimitador. Luego validamos contra la palabra regex. Luego tomamos el primer partido.

ingrese la descripción de la imagen aquí

applejacks01
fuente
La palabra "palabra" está definida por la expresión regular (?<!\w)\w+(?!\w) , donde \westá definida por [abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_], o "caracteres alfanuméricos en ASCII incluyendo el guión bajo".
Leaky Nun
Cuando ejecuto esa expresión regular contra ab! Cd en regex101.com obtengo esto: No se extrajeron grupos de coincidencias. Esto significa que su patrón coincide pero no había (captura (grupos)) en él que coincida con nada en la cadena de asunto. Tal vez estoy haciendo un error en alguna parte ...
applejacks01
¿Por qué necesitaría capturar algo?
Leaky Nun
Sé que este no es el lugar para aprender, pero estoy diciendo que cuando ejecuto esa expresión regular contra ab! Cd no obtengo nada. Entonces, ¿por qué 'ab' sería la salida correcta?
applejacks01
1

Perl 6 , 34 bytes

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

Pruébalo en línea!

Codeblock anónimo que toma entradas curry, como f(n)(string).

Explicación:

->\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
Jo King
fuente
1

Rubí , 30 bytes.

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

Pruébalo en línea!

Un enfoque diferente, solo 1 byte más corto y 3 años después. Por qué no?

GB
fuente
1

APL (NARS), 58 caracteres, 116 bytes

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

⍵ {⍵≤1: ⍵⋄m∊⍨⍵⊃⍺: ⍺∇⍵-1⋄⍵ + 1} ⍺ encuentra dónde comienza la cadena ... Cómo usar y probar:

  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
fuente
0

MATL , 16 15 bytes

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

El cursor está indexado en 1 y después del carácter (como en los casos de prueba).

Pruébalo en línea! O verificar todos los casos de prueba .

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

PowerShell v3 +, 103101 bytes

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

Una especie de solución tonta, pero un enfoque diferente a los demás.

Toma la entrada $acomo el índice basado en 0 de la cadena $n. Luego, encontramos los límites de nuestra palabra. Si bien no hemos llegado al final de la cadena y / o todavía estamos haciendo coincidir caracteres de palabras, nosotros ++$a. Luego, debido a la valla, nos pusimos $i=$a--. A continuación, nos arrastramos hacia atrás, decrementando $ahasta que sea 0o golpeemos un carácter que no sea de palabra. Luego dividimos la cadena de entrada en función de esas dos demarcaciones (con algunos incrementos / decrementos para tener en cuenta OBOE), y-join la juntamos para producir el resultado.

Ejemplos

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
fuente
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 la cadena por caracteres que no son palabras, recordando su posición ( 4==PREG_SPLIT_OFFSET_CAPTURE ), recorre las palabras en bucle hasta alcanzar la posición.
  • Las cadenas PHP están indexadas en 0, cursor antes del carácter, pero pueden estar antes o después de la palabra
Titus
fuente
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

0 indexado.

Busca hacia atrás hasta el primer carácter alfanumérico del índice, luego avanza hasta el último carácter alfanumérico después del índice. Probablemente haya una forma más inteligente de hacer esto.

Intentalo

atlasólogo
fuente
_Se agregó @LeakyNun , aunque no estoy seguro de por qué obtendría un error f('abc',1).
atlasólogo
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
fuente
0

05AB1E , 14 bytes

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

Puerto de @AndersKaseorg Es Pyth respuesta .

1 indexado como los casos de prueba de desafío.

Pruébelo en línea o verifique todos los casos de prueba .

Explicación:

ð«              # 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
fuente