Wybierz słowo wokół danego indeksu w danym ciągu

20

W systemie Windows po dwukrotnym kliknięciu tekstu zostanie wybrane słowo wokół kursora w tekście.

(Ta funkcja ma bardziej skomplikowane właściwości, ale nie będzie wymagana implementacja tego wyzwania).

Na przykład, |bądź kursorem abc de|f ghi.

Następnie po dwukrotnym kliknięciu defwybrany zostanie podciąg .

Wejście wyjście

Otrzymasz dwa wejścia: ciąg znaków i liczbę całkowitą.

Twoim zadaniem jest zwrócenie podłańcuchu ciągu znaków wokół indeksu określonego przez liczbę całkowitą.

Kursor może znajdować się tuż przed lub bezpośrednio po znaku w ciągu o określonym indeksie.

Jeśli korzystasz już wcześniej , proszę podać w swojej odpowiedzi.

Dane techniczne (specyfikacje)

Indeks jest gwarantowana być w środku wyrazu, więc żadne przypadki brzegowe podoba abc |def ghilub abc def| ghi.

Ciąg będzie zawierał tylko drukowalne znaki ASCII (od U ​​+ 0020 do U + 007E).

Słowo „słowo” jest zdefiniowane przez wyrażenie regularne (?<!\w)\w+(?!\w), gdzie \wjest zdefiniowane przez [abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_]lub „znaki alfanumeryczne w ASCII, w tym podkreślenie”.

Indeks może być indeksowany 1 lub 0.

Jeśli korzystasz z indeksu 0, podaj go w swojej odpowiedzi.

Przypadki testowe

Przypadki testowe mają indeks 1, a kursor znajduje się tuż za określonym indeksem.

Pozycja kursora służy wyłącznie do celów demonstracyjnych, których wysłanie nie będzie wymagane.

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
Leaky Nun
źródło
2
Czy ciąg może zawierać znaki nowej linii?
orlp
@orlp Wyzwanie zostało edytowane w celu ograniczenia danych wejściowych do wydruku w formacie ASCII, aby dane wejściowe nie zawierały znaków nowej linii.
FryAmTheEggman
Twoje przypadki testowe nie zawierają żadnych ograniczników innych niż spacje. Co powiesz na słowo we're?
orlp
2
Co powinieneś "ab...cd", 3zwrócić?
Tytus
5
@Titus „Indeks jest gwarantowana być w środku wyrazu”
Martin Ender

Odpowiedzi:

10

V , 10, 9 7 bajtów

À|diwVp

Wypróbuj online!

Ta odpowiedź używa indeksowania 1.

Może to być krótsze, jeśli zrobimy dokładnie to, co mówi tytuł: „ Wybierz słowo wokół podanego indeksu w ciągu”. Moglibyśmy zrobić

À|viw

Który dosłownie wybiera słowo, ale niestety wcale nie zmienia wyniku. Potrzebujemy więc trochę obejścia, aby działało, wycinając go do rejestru, usuwając resztę tekstu, a następnie wklejając go z powrotem.

Wyjaśnienie:

À|          " 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
źródło
5

C, 104 bajty

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

Oczekuje, że wejście na stdin będzie indeksem opartym na 0, po którym będzie spacja lub znak nowej linii, a następnie ciąg. Maksymalna długość słowa wynosi 99 znaków. Na przykład:

2 abc def
orlp
źródło
Naprawdę fajnie jest widzieć C i perl związaną z wyzwaniem opartym na łańcuchach. :D
DJMcMayhem
Czy ciąg wejściowy może mieć więcej niż 100 znaków?
Leaky Nun
@LeakyNun Tak, ale jedno słowo nie może być dłuższe niż 100 znaków.
orlp
Czy chcesz umieścić to wymaganie w swojej odpowiedzi?
Leaky Nun
@DrGreenEggsandIronMan Szkoda, że ​​musiałem naprawić swoją odpowiedź, ponieważ została ona ograniczona do białych znaków :(
lub
4

C (gcc), 94 bajty

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

Zero-indeksowane, definiuje funkcję pobierającą indeks, a następnie ciąg.

orlp
źródło
Uważam, że isalnum(*++p)|*p==95zachowanie jest niezdefiniowane.
owacoder
@owacoder To prawda, ale ważne jest to, że gcc wyrzuca plik wykonywalny, który działa. *++p^95?isalnum(*p):1jest o jeden bajt dłużej, ale działa na każdym kompilatorze.
orlp
Zakładam, że wiodącym miejscem jest literówka? Również tutaj jest leniwy Link IDEone.
FryAmTheEggman
isalnum(*++p)||*p==95działa również dla dodanego jednego bajtu.
owacoder
@FryAmTheEggman Tak, jest już naprawione.
orlp 18.07.16
3

Retina, 22

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

Wypróbuj online! lub zweryfikuj wszystkie przypadki testowe . Zwykły program zajmuje pozycję kursora w jedności, po której następuje nowa linia, a następnie ciąg. Zestaw testowy ma dodatkowy kod do uruchomienia w trybie dla poszczególnych linii, i używa \jako separatora, a dla wygody używa dziesiętnych.

Korzysta z grup równoważących, aby znaleźć pozycję kursora, a następnie cofa się do granicy słowa. Usuwa tekst do słowa, a następnie po słowie.

FryAmTheEggman
źródło
2

C, 115 bajtów

Funkcja f()wymaga łańcucha i indeksu (1-indeksowany) jako parametrów i wypisuje wynik na standardowe wyjście. Kursor powinien znajdować się za określonym znakiem.

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
źródło
2

JavaScript (ES6), 57 bajtów

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

Po prostu wycina ciąg w punkcie kursora (znajdującym się przed znakiem o indeksie 0, który działa tak samo jak po znaku o indeksie 1), a następnie wyodrębnia i konkatenuje sąsiednie fragmenty słowa. Zwraca nawet sensowny wynik, gdy kursor znajduje się na początku, na końcu lub nigdzie w pobliżu słowa.

Neil
źródło
Czy potrzebujesz * w ostatnim wyrażeniu regularnym?
Charlie Wynn
@CharlieWynn Tak, w przeciwnym razie druga walizka testowa tylko by powróciła de.
Neil,
ups, nie miałem szczęścia z testami, które przeprowadziłem
Charlie Wynn
2

Java 8, 86 78 bajtów

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

Nieoznakowane przypadkami testowymi:

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

Dzieli ciąg znaków na znaki niealfanumeryczne, a następnie odejmuje długość każdego podłańcucha plus 1 od określonej pozycji, aż stanie się ujemny. Ponieważ wszelkie powtarzające się znaki nie alfanumeryczne są reprezentowane jako pusty ciąg, logika odejmowania jest znacznie łatwiejsza.

Ten kod nie jest dokładnie testowany, więc chciałbym sprawdzić, czy ktoś może to zepsuć. Biorąc również pod uwagę, że jest to kod Java, dlaczego nie jest to najdłuższa odpowiedź tutaj? : P


źródło
Wiem, że minęły prawie trzy lata, ale (s,p)->można to zrobić s->p->, używając wyrażenia curda lambda (tj java.util.function.Function<String, java.util.function.Function<String, String>> f.). Ponadto Stringmożna go varteraz było zmienić na Javę 10, chociaż oczywiście nie było to wtedy dostępne. Niezależnie od tego, miła odpowiedź. Widzę, że już go gdzieś aktualizowałem. :)
Kevin Cruijssen
2

Pyth, 16 bajtów

+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

Wypróbuj online

Anders Kaseorg
źródło
2

Pyke, 19 bajtów

#Q;cjmli<i+s)lttjR@

Wypróbuj tutaj!

Służy Q;jako brak operacji, aby upewnić się, że pierwsze wejście jest poprawnie umieszczone

#          )   -  first where
   c           -       input.split()
    ml         -      map(len, ^)
      i<       -     ^[:i]
        i+     -    ^+[i]
          s    -   sum(^)
            lt - len(^)-2
niebieski
źródło
Po kliknięciu linku mam błąd 504.
Leaky Nun
@LeakyNun Tak, zabiłem go przez przypadek podczas pisania, dlatego miałem link do hosta lokalnego, wróci
Blue
1
Wygląda na to, że twój program wydaje N, gdzie wybrane jest N-te słowo, ale potrzebujemy pełnego słowa
Value Ink
2

Python 2, 70 66 bajtów

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

Dzieli ciąg według separatorów innych niż słowa, raz na oryginalny ciąg do indeksu kursora, a następnie na ciąg rozpoczynający się od indeksu kursora. Zwraca ostatni element lewego podziału plus pierwszy element prawego podziału. Dzięki Leaky Nun za zaoszczędzenie 4 bajtów!

Cowabunghole
źródło
1

Clojure, 92 bajty

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

Najpierw dzieli ciąg wejściowy w pozycji kna dwa ciągi. Następnie dla tych ciągów znajdź wystąpienia "\w+"i zwróć je jako listę. Następnie połącz ostatni element z pierwszej listy i pierwszy element z drugiej listy.

Zobacz online: https://ideone.com/Dk2FIs

Cliffroot
źródło
1

JavaScript (ES6), 52 bajty

(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
źródło
Dlaczego (\\W+|^)nie(\\W|^)
l4m2
1

Lua, 71 67 bajtów

Woohoo, Lua nie jest najdłuższym rozwiązaniem! Jeszcze jeden bajt za pytonem, ale nie wiem, jak to zagrać w golfa. Indeksy są oparte na 1.

Dzięki @LeakyNun przypominając mi o istnieniu string.match, zapisano 4 bajty

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

Stary 71

Uwaga: wyjaśnienia są nadal oparte na tym, ponieważ dotyczy to również nowego, ale zawiera dodatkowe informacje na temat gmatch

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

Wyjaśnienie

Najpierw rozpakowujemy argumenty gi hponieważ są one krótsze niżarg[x]

g,h=...

Następnie konstruujemy nasz wynik, który jest konkatacją części przed kursorem i po nim.

Pierwsza część łańcucha to

g:sub(1,h)

Chcemy znaleźć słowo na końcu tego, więc używamy funkcji string.gmatch

:gmatch"[%a_]*$"

Ten wzorzec dopasowuje 0..nczasy zestawu znaków alfabetu + podkreślenia na końcu łańcucha. gmatchzwraca iterator z listy dopasowań w postaci funkcji (zgodnie z zasadą zamknięcia), więc wykonujemy go raz, aby uzyskać pierwszą część naszego słowa

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

Drugą część słowa otrzymujemy w ten sam sposób

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

Jedyną różnicą jest to, że nie musimy określać, że chcemy dopasować na początku łańcucha (używając [^%a_]*), ponieważ będzie to dopasowanie zwracane przez iterator przy pierwszym wywołaniu.

Katenkyo
źródło
g:sub(h+1):match"^[%a_]*"?
Leaky Nun
@LeakyNun całkowicie zapomniała o istnieniu match\ o / oszczędza wiele bajtów, dzięki
Katenkyo
-1 dla „indeksów”
Leaky Nun
Nie obchodzi mnie to, nadal -1 dla „indeksów”.
Leaky Nun
1

JavaScript (przy użyciu zewnętrznej biblioteki) (168 bajtów)

(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 do lib: https://github.com/mvegh1/Enumerable/blob/master/linq.js

Objaśnienie kodu: Biblioteka akceptuje ciąg znaków, który jest analizowany w tablicy znaków. Zostaje odwzorowany na obiekt przechowujący indeks i znak. Sekwencja jest podzielona na podsekwencje przy każdym wystąpieniu „”. Podsekwencje są filtrowane poprzez sprawdzenie, czy indeks kursora jest zawarty w indeksie minimalnym i maksymalnym podsekwencji. Następnie bierzemy pierwszą podsekwencję. Następnie przekształcamy się z powrotem w tablicę char. Następnie łączymy wszystkie znaki ze znakiem „” jako separatorem. Następnie sprawdzamy poprawność względem wyrażenia regularnego. Następnie bierzemy pierwszy mecz.

wprowadź opis zdjęcia tutaj

applejacks01
źródło
Słowo „słowo” jest zdefiniowane przez wyrażenie regularne (?<!\w)\w+(?!\w), gdzie \wjest zdefiniowane przez [abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_]lub „znaki alfanumeryczne w ASCII, w tym podkreślenie”.
Leaky Nun
Kiedy uruchamiam wyrażenie regularne przeciwko ab! Cd na regex101.com, otrzymuję to: Nie wyodrębniono grup dopasowania. Oznacza to, że twój wzór pasuje, ale nie było w nim (przechwytywanie (grupy)), które pasowałoby do niczego w ciągu tematu. Może gdzieś popełniam błąd ...
applejacks01
Dlaczego miałbym cokolwiek uchwycić?
Leaky Nun
Wiem, że nie jest to miejsce do nauki, ale mówię, że kiedy uruchamiam wyrażenie regularne przeciwko ab! Cd, nic nie dostaję. Dlaczego więc „ab” byłby prawidłowym wyjściem?
applejacks01
1

Perl 6 , 34 bajtów

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

Wypróbuj online!

Anonimowy blok kodu, który pobiera dane wejściowe curry, jak f(n)(string).

Wyjaśnienie:

->\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
źródło
1

APL (NARS), 58 znaków, 116 bajtów

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

⍵ {⍵≤1: ⍵⋄m∊⍨⍵⊃⍺: ⍺∇⍵-1⋄⍵ + 1} ⍺ znajdź, od czego zacząć ciąg ... Jak używać i testować:

  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
źródło
0

MATL , 16 15 bajtów

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

Kursor jest indeksowany 1 i po znaku (jak w przypadkach testowych).

Wypróbuj online! Lub sprawdź wszystkie przypadki testowe .

'\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
źródło
0

PowerShell v3 +, 103 101 bajtów

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

Rodzaj głupiego rozwiązania, ale inne podejście niż inne.

Pobiera dane wejściowe $ajako indeks ciągu 0 $n. Następnie znajdujemy granice naszego słowa. Chociaż nie dotarliśmy do końca łańcucha i / lub nadal dopasowujemy znaki słów, my ++$a. Następnie, ze względu na ogrodzenie, ustawiliśmy $i=$a--. Następnie pełzamy do tyłu, zmniejszając się, $aaż pojawi się albo 0trafimy na znak inny niż słowo. Następnie przecinamy ciąg wejściowy na podstawie tych dwóch rozgraniczeń (z pewnym przyrostem / zmniejszeniem, aby uwzględnić OBOE) i -joinrazem, aby uzyskać wynik.

Przykłady

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
źródło
select-the-word-around-the-index.ps1
Leaky Nun
0

PHP, 98 bajtów

function f($s,$p){foreach(preg_split('#\W+#',$s,-1,4)as$m)if($m[1]+strlen($m[0])>=$p)return$m[0];}
  • dzieli ciąg znaków na znaki inne niż słowa, zapamiętując ich pozycję ( 4== PREG_SPLIT_OFFSET_CAPTURE), zapętla słowa, aż do osiągnięcia pozycji.
  • Ciągi PHP są indeksowane 0, kursor przed znakiem, ale może znajdować się przed słowem lub po nim
Tytus
źródło
0

Python 3, 112 140 bajtów

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-indeksowane.

Szuka wstecz do pierwszego znaku alfanumerycznego z indeksu, a następnie przechodzi do ostatniego znaku alfanumerycznego po indeksie. Prawdopodobnie jest na to lepszy sposób.

Spróbuj

atlasolog
źródło
@LeakyNun _został dodany, ale nie jestem pewien, dlaczego wystąpił błąd f('abc',1).
atlasolog
0

JavaScript (ES 6), 43 42 bajtów

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

JavaScript (ES 3), 65 bajtów

function(s,n){s.replace(/\w*/g,function(x,y){y<n?s=x:0});alert(s)}
l4m2
źródło
0

05AB1E , 14 bajtów

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

Port @AndersKaseorg @AndersKaseorg .

1-indeksowane, jak przypadki testowe.

Wypróbuj online lub sprawdź wszystkie przypadki testowe .

Wyjaśnienie:

ð«              # 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
źródło