Kürzestes pangrammatisches Fenster

15

Ein Pangram ist ein Satz oder ein Auszug, der alle sechsundzwanzig Buchstaben des Alphabets enthält, wie in dieser Code-Golf-Challenge gezeigt wird . Ein pangrammatisches Fenster ist jedoch ein Pangram in Form eines Textsegments, das in der Mitte eines Wortes enden oder beginnen kann und sich irgendwo in einem größeren Werk befindet. Diese kommen natürlich überall vor und sind richtige Untergruppen von echten Pangrams. Es wäre also schon langweilig, zu überprüfen, ob etwas ein pangrammatisches Fenster enthält, und das war auch schon früher der Fall.

Wir sind also daran interessiert, die kleinste zu finden, die es in einem bestimmten Textstück gibt, basierend auf seiner Buchstabenlänge! In kürzester Zeit Code in Bytes natürlich passend zum Thema.

Regeln und Richtlinien

  • Empfangen Sie eine Zeichenfolge als Eingabe und geben Sie die Zeichenfolge des kleinsten pangrammatischen Fensters in der Eingabe zurück, falls vorhanden. Ist dies nicht der Fall, geben Sie entweder einen Booleschen Wert oder eine leere Zeichenfolge zurück.
  • Ob eine Zeichenfolge ein pangrammatisches Fenster ist oder nicht, ist unabhängig von der Groß- und Kleinschreibung und hängt nur von den 26 Buchstaben ab, nicht von Satzzeichen oder Zahlen oder anderen ungeraden Symbolen.
  • In ähnlicher Weise ist die Buchstabenlänge eines pangrammatischen Fensters die Gesamtzahl der Buchstaben, die allein darin vorkommen, und nicht einfach die Anzahl aller Zeichen. Der zurückgegebene Wert muss basierend auf dieser Anzahl am kleinsten sein. Wir sind schließlich Linguisten, keine Programmierer.
  • Die Ausgabe eines pangrammatischen Fensters muss jedoch eine exakte Teilzeichenfolge der Eingabe sein, die die gleiche Groß- und Kleinschreibung und Interpunktion usw. enthält.
  • Wenn mehrere kürzeste pangrammatische Fenster mit derselben Buchstabenlänge vorhanden sind, geben Sie eines davon zurück.

Testfälle

'This isn't a pangram.'
==> False

'Everyone knows about that infamous Quick-Brown-Fox (the one who jumped over some lazy ignoramus of a dog so many years ago).'
==> 'Quick-Brown-Fox (the one who jumped over some lazy ig'

'"The five boxing wizards jump quickly." stated Johnny, before beginning to recite the alphabet with a bunch of semicolons in the middle. "ABCDEFGHI;;;;;;;;;;;;;;;JKLMNOPQRSTUVWXYZ!" he shouted to the heavens.'
==> 'ABCDEFGHI;;;;;;;;;;;;;;;JKLMNOPQRSTUVWXYZ'
Reecer6
quelle
1
Warum wird der letzte Testfall nicht The five boxing wizards jump quicklyzurückgegeben?
Blau
1
Ist im zweiten Fall der Raum vor dem Feld zulässig Q? Es erhöht die Anzahl der Buchstaben nicht.
Neil
2
@muddyfish Weil es 31 Buchstaben hat, während die erwartete Ausgabe nur 26 hat.
Martin Ender
4
Schöne erste Frage!
17.
2
Ja. Kein Grund sollte es nicht sein. Nehmen Sie das "wahre" Minimum im Sinne der Frage, aber es ist nicht notwendig.
Reecer6

Antworten:

6

Pyth, 20 16 14 Bytes

hol@GNf!-GrT0.:

Erläuterung:

             .: - substrings of input()
      f!-GrT0   - filter to ones which contain the alphabet
 ol@GN          - sort by number of alphabetical chars
h               - ^[0]

      f!-GrT0   - filter(lambda T:V, substrings)
          rT0   -    T.lower()
        -G      -   alphabet-^
       !        -  not ^

 o              - sort(^, lambda N:V)
   @GN          -   filter_presence(alphabet, N)
  l             -  len(^)

Probieren Sie es hier aus!

Wenn es keine richtige Lösung gibt, wird das Programm mit einem Fehler ohne Ausgabe an stdout beendet.

Blau
quelle
Sie scheinen den Code im ersten Codeblock nicht aktualisiert zu haben. Ist auch !-GrT0kürzer für den Filterzustand, glaube ich. Ich denke auch, dass Sie das brauchen l, damit die Sortierung richtig funktioniert.
FryAmTheEggman
Oh, ich habe falsch geschrieben, ich meinte den Link. In Ihrem Link haben Sie noch die l, und ohne sie erhalten Sie unterschiedliche Ergebnisse . Ich glaube, das Problem sind wiederholte Briefe, aber ich bin nicht 100% sicher.
FryAmTheEggman
Es ist also wichtig - und danke für die Optimierung!
Blau
3

Pyth - 22 Bytes

\ o / FGITW!

h+ol@GrNZf}GS{rTZ.:z)k

Test Suite .

Maltysen
quelle
2

Ruby, 100 Bytes

Gibt nil zurück, wenn kein Fenster gefunden wird.

->s{r=0..s.size
(r.map{|i|s[i,r.find{|j|(?a..?z).all?{|c|s[i,j]=~/#{c}/i}}||0]}-['']).min_by &:size}
Wert Tinte
quelle
2

JavaScript (ES6), 139 138 136 Bytes

s=>[r=l="",...s].map((_,b,a)=>a.map((c,i)=>i>b&&(t+=c,z=parseInt(c,36))>9&&(v++,n+=!m[z],m[z]=n<26||l&&v>l||(r=t,l=v)),t=m=[],v=n=0))&&r

2 Bytes gespart dank @Neil!

Eingerückt

var solution =

s=>
  [r=l="",...s].map((_,b,a)=> // b = index of start of window to check
    a.map((c,i)=>
      i>b&&(
        t+=c,
        z=parseInt(c,36)
      )>9&&(
        v++,
        n+=!m[z],
        m[z]=
          n<26||
          v>l&&l||(
            r=t,
            l=v
          )
      ),
      t=m=[],
      v=n=0
    )
  )
  &&r
<textarea cols="70" rows="6" id="input">Everyone knows about that infamous Quick-Brown-Fox (the one who jumped over some lazy ignoramus of a dog so many years ago).</textarea><br /><button onclick="result.textContent=solution(input.value)">Go</button><pre id="result"></pre>

user81655
quelle
Kannst du nicht benutzen [r=l="",...s].map((_,b,a)=>?
Neil
@Neil Danke, ich vergesse immer den dritten Parameter in der mapFunktion.
user81655
Ich denke, @ edc65 kann dies jedoch übertreffen. Ich habe den Code für seine explodierten Teilzeichenfolgen mit dem für seinen Pangram-Tester zusammengeführt und am Ende eine 134-Byte-Funktion erhalten.
Neil
Mein bisher bestes
Ergebnis
Leider habe ich nicht daran gedacht, es zu speichern, und mein PC ist abgestürzt. Jetzt weiß ich nicht, was ich hatte. Das Beste, was ich jetzt tun kann, sind 138 Bytes.
Neil
2

PowerShell v2 +, 218 Byte

param($a)$z=@{};(0..($b=$a.length-1)|%{($i=$_)..$b|%{-join$a[$i..$_]}})|%{$y=$_;$j=1;65..90|%{$j*=$y.ToUpper().IndexOf([char]$_)+1};if($j){$z[($y-replace'[^A-Za-z]').Length]=$y}}
($z.GetEnumerator()|sort Name)[0].Value

Ja, Teilstring-Manipulation (es gibt keine integrierten Funktionen) ist also nicht wirklich die Stärke von PowerShell ...

Wir nehmen Eingaben param($a)und setzen eine neue leere Hashtabelle $z. Dies ist unser Speicher für pangrammatische Teilstrings.

Unter Verwendung einer geringfügigen Änderung meines Codes aus Exploded Substrings konstruieren wir alle Teilzeichenfolgen der Eingabe. Ja, sogar Teilzeichenfolgen, die nur aus einem Zeichen bestehen. Dies ist , nicht der . ;-)

Alle diese Teilzeichenfolgen werden in Parens eingekapselt und in eine andere Schleife mit geleitet |%{...}. Wir setzen vorübergehend $yunseren aktuellen Teilstring, setzen einen Hilfszähler $jund starten eine weitere Schleife 65..90|%{...}, bequem über die ASCII-Zeichencodes für Großbuchstaben. Jede innere Schleife, die wir nehmen $y, wird in Großbuchstaben geschrieben und das .IndexOfjeweilige Zeichen herausgezogen. Da dies zurückgibt, -1wenn es nicht gefunden wird, berechnen wir +1das Ergebnis, bevor wir es multiplizieren $j. Dies stellt sicher, dass wenn eines der Zeichen nicht gefunden wird, $jes gleich Null ist.

Welches ist genau das, worum es ifgeht. Wenn $jungleich Null ist, bedeutet dies, dass jeder Buchstabe mindestens einmal in der Teilzeichenfolge gefunden $ywurde. Daher müssen wir diesen zu unserem Kandidatenpool hinzufügen. Wir tun dies , indem sie $yund -replaceing jeden nicht-Brief mit nichts, was uns die Brief-Länge dieser Teilzeichen bekommt. Wir verwenden das als Index für die Hash-Tabelle $zund speichern es $yan diesem Index. Dies hat den Nachteil, dass Teilzeichenfolgen mit der gleichen Buchstabenlänge überschrieben werden, die in der ursprünglichen Zeichenfolge "am weitesten" vorkommt. Dies ist jedoch nach den Regeln zulässig, da es nur um die Buchstabenlänge geht.

Schließlich müssen wir $zdie kleinsten sortieren und herausziehen. Wir haben die verwenden .GetEnumeratorAnruf , um auf den zu sortieren Inneren Objekte $z , dann sortdie auf Name(dh die Länge Index von oben), die Auswahl [0]ten (dh die kürzeste), und zum Ausgeben von dessen .Value(dh die Teilzeichen ). Wenn keine solche Teilzeichenfolge passt, wird ein error ( Cannot index into a null array) $zausgegeben, wenn versucht wird, einen Index zu erstellen, und es wird nichts ausgegeben, was in PowerShell falsch ist. (Der dritte Testfall hat eine explizite Besetzung [bool], um dies zu zeigen.)

Testfälle

PS C:\Tools\Scripts> .\golfing\shortest-pangrammatic-window.ps1 '"The five boxing wizards jump quickly." stated Johnny, before beginning to recite the alphabet with a bunch of semicolons in the middle. "ABCDEFGHI;;;;;;;;;;;;;;;JKLMNOPQRSTUVWXYZ!" he shouted to the heavens.'
ABCDEFGHI;;;;;;;;;;;;;;;JKLMNOPQRSTUVWXYZ!" 

PS C:\Tools\Scripts> .\golfing\shortest-pangrammatic-window.ps1 'Everyone knows about that infamous Quick-Brown-Fox (the one who jumped over some lazy ignoramus of a dog so many years ago).'
Quick-Brown-Fox (the one who jumped over some lazy ig

PS C:\Tools\Scripts> [bool](.\golfing\shortest-pangrammatic-window.ps1 "This isn't a pangram.")
Cannot index into a null array.
At C:\Tools\Scripts\golfing\shortest-pangrammatic-window.ps1:2 char:1
+ ($z.GetEnumerator()|sort Name)[0].Value
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : NullArray

False
AdmBorkBork
quelle
2

Haskell, 180 Bytes

Das war schwer, aber sehr lustig ohne Importe.

l=['a'..'z']
u=['A'..'Z']
f&[]=[];f&x=x:f&f x
g#h=(.g).h.g
f x|v<-[y|y<-(tail&)=<<(init&x),and$zipWith((`elem`y)#(||))l u]=last$[]:[z|z<-v,all((length.filter(`elem`l++u))#(<=)$z)v]

Viel weniger Golf gespielt:

lowerCase = ['a'..'z']
upperCase = ['A'..'Z']

f & x = takeWhile (not . null) $ iterate f x

(#) = flip on

subStrings x = (tail &) =<< (init & x)

pangram p = and $ zipWith ((`elem` p) # (||)) lowerCase upperCase

leqLetters x y = (length . filter (`elem` lowerCase ++ upperCase)) # (<=)

fewestLetters xs = [ x | x <- xs, all (leqLetters x) xs]

safeHead [] = ""
safeHead xs = head xs

f x = safeHead . fewestLetters . filter pangram . subStrings

Überraschung, Überraschung: Es ist sehr langsam.

Michael Klein
quelle
2

Oracle SQL 11.2, 461 Byte

WITH s AS (SELECT SUBSTR(:1,LEVEL,1)c,LEVEL p FROM DUAL CONNECT BY LEVEL<=LENGTH(:1)),v(s,f,l)AS(SELECT c,p,p FROM s UNION ALL SELECT s||c,f,p FROM v,s WHERE p=l+1),c AS(SELECT CHR(96+LEVEL)c FROM DUAL CONNECT BY LEVEL<27),a AS(SELECT LISTAGG(c)WITHIN GROUP(ORDER BY 1) a FROM c)SELECT MIN(s)KEEP(DENSE_RANK FIRST ORDER BY LENGTH(s)-NVL(LENGTH(TRANSLATE(LOWER(s),' '||a,' ')),0))FROM(SELECT s,f,SUM(SIGN(INSTR(LOWER(s),c)))x FROM v,c GROUP BY s,f),a WHERE x=26;

Nicht golfen

WITH s AS (SELECT SUBSTR(:1,LEVEL,1)c,LEVEL p FROM DUAL CONNECT BY LEVEL<=LENGTH(:1))
,v(s,f,l) AS
(
  SELECT c,p,p FROM s
  UNION ALL
  SELECT s||c,f,p FROM v,s WHERE p=l+1 
)
,c AS(SELECT CHR(96+LEVEL)c FROM DUAL CONNECT BY LEVEL<27)
,a AS(SELECT LISTAGG(c)WITHIN GROUP(ORDER BY 1) a FROM c)
SELECT MIN(s)KEEP(DENSE_RANK FIRST ORDER BY LENGTH(s)-NVL(LENGTH(TRANSLATE(LOWER(s),' '||a,' ')),0))
FROM(SELECT s,f,SUM(SIGN(INSTR(LOWER(s),c)))x FROM v,c GROUP BY s,f),a
WHERE x=26

Die sAnsicht teilt die Eingabe in Zeichen auf und gibt auch die Position jedes Zeichens zurück.

Die rekursive Ansicht vgibt jede Teilzeichenfolge der Eingabe zurück.
S ist die Teilzeichenfolge
der Position des ersten Zeichens der Teilzeichenfolge
l die Position des letzten Zeichens, das der aktuellen Teilzeichenfolge hinzugefügt wurde

Die cAnsicht gibt das Alphabet nacheinander aus

Die aAnsicht gibt das als einzelne Zeichenfolge verkettete Alphabet zurück

SELECT s,f,SUM(SIGN(INSTR(LOWER(s),c))
Gibt für jeden Teilstring die Anzahl der darin enthaltenen unterschiedlichen Buchstaben
INSTRzurück. Gibt die Position eines Buchstabens im Teilstring zurück, 0, wenn nicht vorhanden,
SIGN1, wenn pos> 0, 0, wenn pos = 0

WHERE x=26
Filtert die Teilzeichenfolge, die das gesamte Alphabet enthält

TRANSLATE(LOWER(s),' '||a,' ')
Löscht jeden Buchstaben aus der Teilzeichenfolge

LENGTH(s)-NVL(LENGTH(TRANSLATE(LOWER(s),' '||a,' ')
Länge in Buchstaben ist die Länge des Teilstrings minus der Länge des Teilstrings ohne Buchstaben

SELECT MIN(s)KEEP(DENSE_RANK FIRST ORDER BY LENGTH(s)-NVL(LENGTH(TRANSLATE(LOWER(s),' '||a,' ')),0))
Behält nur den Teilstring mit der kleineren Buchstabenanzahl bei.
Wenn es mehr als eine gibt, wird die erste, in aufsteigender Reihenfolge sortiert, beibehalten

Jeto
quelle
2

Python 3, 171, 167, 163, 157 , 149 Bytes.

4 Bytes gespart dank DSM.
8 Bytes dank RootTwo gespart.

lambda x,r=range:min([x[i:j]for i in r(len(x))for j in r(len(x))if{*map(chr,r(65,91))}<={*x[i:j].upper()}]or' ',key=lambda y:sum(map(str.isalpha,y)))

Nach der Anzahl der Buchstaben sortieren zu müssen, bringt mich um.

Testfälle:

assert f("This isn't a pangram.") == ' '
assert f("Everyone knows about that infamous Quick-Brown-Fox (the one who jumped over some lazy ignoramus of a dog so many years ago).") == ' Quick-Brown-Fox (the one who jumped over some lazy ig', f("Everyone knows about that infamous Quick-Brown-Fox (the one who jumped over some lazy ignoramus of a dog so many years ago).")
assert f('"The five boxing wizards jump quickly." stated Johnny, before beginning to recite the alphabet with a bunch of semicolons in the middle. "ABCDEFGHI;;;;;;;;;;;;;;;JKLMNOPQRSTUVWXYZ!" he shouted to the heavens.') == '. "ABCDEFGHI;;;;;;;;;;;;;;;JKLMNOPQRSTUVWXYZ', f('"The five boxing wizards jump quickly." stated Johnny, before beginning to recite the alphabet with a bunch of semicolons in the middle. "ABCDEFGHI;;;;;;;;;;;;;;;JKLMNOPQRSTUVWXYZ!" he shouted to the heavens.')
Morgan Thrapp
quelle
Denken Sie nicht, dass .upper()die Schlüsselfunktion benötigt wird.
RootTwo
@RootTwo Ups, du hast recht. Vielen Dank.
Morgan Thrapp
1

PowerShell (v4), 198 bis 156 Byte

param($s)
-join(@(1..($y=$s.Length)|%{$w=$_
0..$y|%{(,@($s[$_..($_+$w)]))}}|?{($_-match'[a-z]'|sort -U).Count-eq26}|sort -Pr {($_-match'[a-z]').count})[0])


# Previous 198 byte golf
$a,$b,$c=@(1..($s="$args").Length|%{$w=$_
0..($s.Length-$w)|%{if((($t=$s[$_..($_+$w)]-match'[a-z]')|sort -u).Count-eq26){(,@($t.Length,$_,$w))}}}|sort -pr{$_[0]})[0]
(-join($s[$b..($b+$c)]),'')[!$a]

Testfälle

PS C:\> .\PangramWindow.ps1 "This isn't a pangram."


PS C:\> .\PangramWindow.ps1 'Everyone knows about that infamous Quick-Brown-Fox (the one who jumped over some lazy ignoramus of a dog so many years ago).'
Quick-Brown-Fox (the one who jumped over some lazy ig

PS C:\> .\PangramWindow.ps1 '"The five boxing wizards jump quickly." stated Johnny, before beginning to recite the alphabet with a bunch of semicolons in the middle. "ABCDEFGHI;;;;;;;;;;;;;;;JKLMNOPQRSTUVWXYZ!" he shouted to the heavens.'
ABCDEFGHI;;;;;;;;;;;;;;;JKLMNOPQRSTUVWXYZ!

Ungolfed Erklärung des Originals

Es ist eine verschachtelte Brute-Force-Schleife, die Schiebefenster aller Größen ermöglicht:

.SubString(0, 1) -> slide window over the string
.SubString(0, 2) -> slide window over the string
..
.SubString(0, string.Length) -> slide window over the string

Für jedes Fenster wird nur nach Buchstaben gefiltert (standardmäßig wird zwischen Groß- und Kleinschreibung unterschieden), die verbleibenden Zeichen werden durch einen eindeutigen Filter geleitet und es wird geprüft, ob der Pangram-Test 26 eindeutige Zeichen enthält.

Alle Fenster mit Pangrams werden in Dreiergruppen von (Anzahl der Buchstaben einschließlich Dupes, Startindex, Fensterlänge einschließlich Interpunktion) umgewandelt , die sortiert werden, um die kürzeste nach der Gesamtzahl der Zeichen zu finden, die erste wird ausgewählt und die Ausgabezeichenfolge daraus erstellt .

Es gibt eine Menge Indizierungen außerhalb der Grenzen des Strings, für die PowerShell sinnvollerweise $ null zurückgibt, anstatt Ausnahmen auszulösen.

NB. Der neue 156-Byte-One-Ansatz ist derselbe, wurde jedoch umgeschrieben, um die Pipeline wesentlich stärker zu nutzen.

$string = "$args"

# increasing window widths, outer loop
$allPangramWindows =  foreach ($windowWidth in 1..$string.Length) {

    # sliding windows over string, inner loop
    0..($string.Length - $windowWidth) | ForEach {

        # slice window out of string, returns a char array
        $tmp = $string[$_..($_+$windowWidth)]

        # filter the char array to drop not-letters
        $tmp = $tmp -match '[a-z]'

        # Drop duplicate letters
        $tmpNoDupes = $tmp | sort -Unique

        # If we're left with a 26 character array, this is a pangrammatic window. Output
        # a PowerShell-style tuple of count of letters, start index, width.
        if($tmpNoDupes.Count -eq 26){
            (,@($tmp.Length,$_,$windowWidth))
        }
    }
}

# Force the result into an array (to handle no-results), sort it
# by the first element (num of letters in the window, total)
$allPangramWindows = @( $allPangramWindows | sort -Property {$_[0]} )

# take element 0, a window with the fewest letters
$windowCharCount, $windowStart, $WindowEnd = $allPangramWindows[0]

# uses the results to find the original string with punctuation and whitespace
if ($windowLen) {
    $string[$windowStart..($windowStart + $windowLen)] -join ''
}

NB. Ich bin mir nicht sicher, ob die ungolfed Version funktioniert, weil ich sie nicht geschrieben habe, sondern nur zur Erläuterung.

TessellatingHeckler
quelle
0

Haskell, 123 Bytes

import Data.Lists
import Data.Char
h x=take 1$sortOn((1<$).filter isAlpha)[e|e<-powerslice x,['a'..'z']\\map toLower e==""]

Definiert eine Funktion h, die die leere Liste zurückgibt, wenn kein pangrammatisches Fenster oder eine Liste mit einem Element mit dem minimalen Fenster vorhanden ist. Anwendungsbeispiel:

*Main>  h "'The five boxing wizards jump quickly.' stated Johnny, before beginning to recite the alphabet with a bunch of semicolons in the middle. 'ABCDEFGHI;;;;;;;;;;;;;;;JKLMNOPQRSTUVWXYZ!' he shouted to the heavens."
[". 'ABCDEFGHI;;;;;;;;;;;;;;;JKLMNOPQRSTUVWXYZ"]

Wie es funktioniert:

          [e|e<-powerslice x                  ]  -- for all continuous subsequences
                                                 -- e of the input  
                ,['a'..'z']\\map toLower e==""   -- keep those where the list
                                                 -- difference with all letters is
                                                 -- empty, i.e. every letter appears
                                                 -- at least once
    sortOn((1<$).filter isAlpha)                 -- sort all remaining lists on
                                                 -- their length after removing all
                                                 -- non-letters -> (1<$) see below
take 1                                           -- take the first, i.e. the minimum


calculating the length of a list: we're not interested in the length itself, but
in the relative order of the length. (1<$) replaces each element in a list with
the number 1, e.g. "abc" -> "111", "abcd" -> "1111", etc. Such '1'-strings have
the same order as the length of the original list. One byte saved!
nimi
quelle