para name metadatos keywords google etiquetas ejemplos description content buscadores code-golf text-parsing language-agnostic rosetta-stone

code-golf - name - seo html



Code Golf: compilación rápida de palabras clave a partir de texto, incluyendo#de instancias (13)

Ya he resuelto esta solución para mí con PHP, pero tengo curiosidad de cómo se podría hacer de manera diferente, incluso mejor. Los dos idiomas que más me interesan son PHP y Javascript, pero me gustaría ver qué tan rápido se puede hacer esto en cualquier otro idioma principal hoy en día (principalmente C #, Java, etc.).

  1. Devuelve solo palabras con una ocurrencia mayor que X
  2. Devuelve solo palabras con una longitud mayor que Y
  3. Ignore términos comunes como "y, es, el, etc."
  4. Siéntase libre de quitar la puntuación antes del procesamiento (es decir, "John''s" se convierte en "John")
  5. Devuelve resultados en una colección / matriz

Crédito adicional

  1. Mantenga declaraciones citadas juntas, (es decir. "Eran ''demasiado buenas para ser verdad'' aparentemente")
    Donde "demasiado bueno para ser verdad" sería la afirmación real

Crédito Extra-Extra

  1. ¿Puede su secuencia de comandos determinar las palabras que deben mantenerse juntas en función de su frecuencia de encontrarse juntas? Esto se hace sin conocer las palabras de antemano. Ejemplo:
    * "La mosca de la fruta es una gran cosa cuando se trata de investigación médica. Se han realizado muchos estudios sobre la mosca de la fruta en el pasado, y ha dado lugar a muchos avances. En el futuro, la mosca de la fruta seguirá estudiándose, pero nuestros métodos pueden cambiar ". *
    Claramente, la palabra aquí es "mosca de la fruta", que es fácil de encontrar. ¿Puede la secuencia de comandos de búsqueda de escritura determinar esto también?

Texto fuente: http://sampsonresume.com/labs/c.txt

Formato de respuesta

  1. Sería genial ver los resultados de su código, salida, además de cuánto duró la operación.

REBOL

Verbose, tal vez, definitivamente no es un ganador, pero hace el trabajo.

min-length: 0 min-count: 0 common-words: [ "a" "an" "as" "and" "are" "by" "for" "from" "in" "is" "it" "its" "the" "of" "or" "to" "until" ] add-word: func [ word [string!] /local count letter non-letter temp rules match ][ ; Strip out punctuation temp: copy {} letter: charset [ #"a" - #"z" #"A" - #"Z" #" " ] non-letter: complement letter rules: [ some [ copy match letter (append temp match) | non-letter ] ] parse/all word rules word: temp ; If we end up with nothing, bail if 0 == length? word [ exit ] ; Check length if min-length > length? word [ exit ] ; Ignore common words ignore: if find common-words word [ exit ] ; OK, its good. Add it. either found? count: select words word [ words/(word): count + 1 ][ repend words [word 1] ] ] rules: [ some [ {"} copy word to {"} (add-word word) {"} | copy word to { } (add-word word) { } ] end ] words: copy [] parse/all read %c.txt rules result: copy [] foreach word words [ if string? word [ count: words/:word if count >= min-count [ append result word ] ] ] sort result foreach word result [ print word ]

El resultado es:

act actions all allows also any appear arbitrary arguments assign assigned based be because been before below between braces branches break builtin but C C like any other language has its blemishes Some of the operators have the wrong precedence some parts of the syntax could be better call called calls can care case char code columnbased comma Comments common compiler conditional consisting contain contains continue control controlflow criticized Cs curly brackets declarations define definitions degree delimiters designated directly dowhile each effect effects either enclosed enclosing end entry enum evaluated evaluation evaluations even example executed execution exert expression expressionExpressions expressions familiarity file followed following format FORTRAN freeform function functions goto has high However identified ifelse imperative include including initialization innermost int integer interleaved Introduction iterative Kernighan keywords label language languages languagesAlthough leave limit lineEach loop looping many may mimicked modify more most name needed new next nonstructured normal object obtain occur often omitted on operands operator operators optimization order other perhaps permits points programmers programming provides rather reinitialization reliable requires reserve reserved restrictions results return Ritchie say scope Sections see selects semicolon separate sequence sequence point sequential several side single skip sometimes source specify statement statements storage struct Structured structuresAs such supported switch syntax testing textlinebased than There This turn type types union Unlike unspecified use used uses using usually value values variable variables variety which while whitespace widespread will within writing


Rubí

Cuando se "minifica", esta implementación tiene 165 caracteres de longitud. Utiliza array#inject para dar un valor de inicio (un objeto Hash con un valor predeterminado de 0) y luego recorre los elementos, que luego se enrollan en el hash; el resultado se selecciona a partir de la frecuencia mínima.

Tenga en cuenta que no conté el tamaño de las palabras para omitir, que es una constante externa. Cuando la constante se cuenta también, la solución tiene 244 caracteres de largo.

Los apóstrofes y los guiones no se eliminan, sino que se incluyen; su uso modifica la palabra y, por lo tanto, no se puede quitar simplemente sin eliminar toda la información más allá del símbolo.

Implementación

CommonWords = %w(the a an but and is not or as of to in for by be may has can its it''s) def get_keywords(text, minFreq=0, minLen=2) text.scan(/(?:/b)[a-z''-]{#{minLen},}(?=/b)/i). inject(Hash.new(0)) do |result,w| w.downcase! result[w] += 1 unless CommonWords.include?(w) result end.select { |k,n| n >= minFreq } end

Banco de pruebas

require ''net/http'' keywords = get_keywords(Net::HTTP.get(''www.sampsonresume.com'',''/labs/c.txt''), 3) keywords.sort.each { |name,count| puts "#{name} x #{count} times" }

Resultados de la prueba

code x 4 times declarations x 4 times each x 3 times execution x 3 times expression x 4 times function x 5 times keywords x 3 times language x 3 times languages x 3 times new x 3 times operators x 4 times programming x 3 times statement x 7 times statements x 4 times such x 3 times types x 3 times variables x 3 times which x 4 times


C # 3.0 (con LINQ)

Aquí está mi solución. Hace uso de algunas características bastante agradables de LINQ / métodos de extensión para mantener el código corto.

public static Dictionary<string, int> GetKeywords(string text, int minCount, int minLength) { var commonWords = new string[] { "and", "is", "the", "as", "of", "to", "or", "in", "for", "by", "an", "be", "may", "has", "can", "its"}; var words = Regex.Replace(text.ToLower(), @"[,.?//;:/(/)]", string.Empty).Split('' ''); var occurrences = words.Distinct().Except(commonWords).Select(w => new { Word = w, Count = words.Count(s => s == w) }); return occurrences.Where(wo => wo.Count >= minCount && wo.Word.Length >= minLength) .ToDictionary(wo => wo.Word, wo => wo.Count); }

Sin embargo, esto está lejos del método más eficiente, siendo O(n^2) con el número de palabras, en lugar de O(n) , lo cual es óptimo en este caso, creo. Veré si puedo crear un método un poco más largo que sea más eficiente.

Aquí están los resultados de la función ejecutada en el texto de muestra (ocurrencias mínimas: 3, duración mínima: 2).

3 x such 4 x code 4 x which 4 x declarations 5 x function 4 x statements 3 x new 3 x types 3 x keywords 7 x statement 3 x language 3 x expression 3 x execution 3 x programming 4 x operators 3 x variables

Y mi programa de prueba:

static void Main(string[] args) { string sampleText; using (var client = new WebClient()) sampleText = client.DownloadString("http://sampsonresume.com/labs/c.txt"); var keywords = GetKeywords(sampleText, 3, 2); foreach (var entry in keywords) Console.WriteLine("{0} x {1}", entry.Value.ToString().PadLeft(3), entry.Key); Console.ReadKey(true); }


Perl en solo 43 caracteres.

perl -MYAML -anE''$_{$_}++for@F;say Dump/%_''

Aquí hay un ejemplo de su uso:

echo a a a b b c d e aa | perl -MYAML -anE''$_{$_}++for@F;say Dump /%_'' --- a: 3 aa: 1 b: 2 c: 1 d: 1 e: 1

Si necesita enumerar solo las versiones en minúsculas, se requieren dos caracteres más.

perl -MYAML -anE''$_{lc$_}++for@F;say Dump/%_''

Para que funcione en el texto especificado requiere 58 caracteres.

curl http://sampsonresume.com/labs/c.txt | perl -MYAML -F''/W+'' -anE''$_{lc$_}++for@F;END{say Dump/%_}''

real 0m0.679s user 0m0.304s sys 0m0.084s

Aquí está el último ejemplo ampliado un poco.

#! perl use 5.010; use YAML; while( my $line = <> ){ for my $elem ( split ''/W+'', $line ){ $_{ lc $elem }++ } END{ say Dump /%_; } }


Aquí está mi variante, en PHP:

$str = implode(file(''c.txt'')); $tok = strtok($str, " .,;()/r/n/t"); $splitters = ''/s.,/(/);?:''; // string splitters $array = preg_split( "/[" . $splitters . "]*///"([^///"]+)///"[" . $splitters . "]*|[" . $splitters . "]+/", $str, 0, PREG_SPLIT_DELIM_CAPTURE ); foreach($array as $key) { $res[$key] = $res[$key]+1; } $splitters = ''/s.,/(/)/{/};?:''; // string splitters $array = preg_split( "/[" . $splitters . "]*///"([^///"]+)///"[" . $splitters . "]*|[" . $splitters . "]+/", $str, 0, PREG_SPLIT_DELIM_CAPTURE ); foreach($array as $key) { $res[$key] = $res[$key]+1; } unset($res[''the'']); unset($res[''and'']); unset($res[''to'']); unset($res[''of'']); unset($res[''by'']); unset($res[''a'']); unset($res[''as'']); unset($res[''is'']); unset($res[''in'']); unset($res['''']); arsort($res); //var_dump($res); // concordance foreach ($res AS $word => $rarity) echo $word . '' <b>x</b> '' . $rarity . ''<br/>''; foreach ($array as $word) { // words longer than n (=5) // if(strlen($word) > 5)echo $word.''<br/>''; }

Y salida:

statement x 7 be x 7 C x 5 may x 5 for x 5 or x 5 The x 5 as x 5 expression x 4 statements x 4 code x 4 function x 4 which x 4 an x 4 declarations x 3 new x 3 execution x 3 types x 3 such x 3 variables x 3 can x 3 languages x 3 operators x 3 end x 2 programming x 2 evaluated x 2 functions x 2 definitions x 2 keywords x 2 followed x 2 contain x 2 several x 2 side x 2 most x 2 has x 2 its x 2 called x 2 specify x 2 reinitialization x 2 use x 2 either x 2 each x 2 all x 2 built-in x 2 source x 2 are x 2 storage x 2 than x 2 effects x 1 including x 1 arguments x 1 order x 1 even x 1 unspecified x 1 evaluations x 1 operands x 1 interleaved x 1 However x 1 value x 1 branches x 1 goto x 1 directly x 1 designated x 1 label x 1 non-structured x 1 also x 1 enclosing x 1 innermost x 1 loop x 1 skip x 1 There x 1 within x 1 switch x 1 Expressions x 1 integer x 1 variety x 1 see x 1 below x 1 will x 1 on x 1 selects x 1 case x 1 executed x 1 based x 1 calls x 1 from x 1 because x 1 many x 1 widespread x 1 familiarity x 1 C''s x 1 mimicked x 1 Although x 1 reliable x 1 obtain x 1 results x 1 needed x 1 other x 1 syntax x 1 often x 1 Introduction x 1 say x 1 Programming x 1 Language x 1 C, like any other language, has its blemishes. Some of the operators have the wrong precedence; some parts of the syntax could be better. x 1 Ritchie x 1 Kernighan x 1 been x 1 criticized x 1 For x 1 example x 1 care x 1 more x 1 leave x 1 return x 1 call x 1 && x 1 || x 1 entry x 1 include x 1 next x 1 before x 1 sequence point x 1 sequence x 1 points x 1 comma x 1 operator x 1 but x 1 compiler x 1 requires x 1 programmers x 1 exert x 1 optimization x 1 object x 1 This x 1 permits x 1 high x 1 degree x 1 occur x 1 Structured x 1 using x 1 struct x 1 union x 1 enum x 1 define x 1 Declarations x 1 file x 1 contains x 1 Function x 1 turn x 1 assign x 1 perhaps x 1 Keywords x 1 char x 1 int x 1 Sections x 1 name x 1 variable x 1 reserve x 1 usually x 1 writing x 1 type x 1 Each x 1 line x 1 format x 1 rather x 1 column-based x 1 text-line-based x 1 whitespace x 1 arbitrary x 1 FORTRAN x 1 77 x 1 free-form x 1 allows x 1 restrictions x 1 Comments x 1 C99 x 1 following x 1 // x 1 until x 1 */ x 1 /* x 1 appear x 1 between x 1 delimiters x 1 enclosed x 1 braces x 1 supported x 1 if x 1 -else x 1 conditional x 1 Unlike x 1 reserved x 1 sequential x 1 provides x 1 control-flow x 1 identified x 1 do-while x 1 while x 1 any x 1 omitted x 1 break x 1 continue x 1 expressions x 1 testing x 1 iterative x 1 looping x 1 separate x 1 initialization x 1 normal x 1 modify x 1 control x 1 structures x 1 As x 1 imperative x 1 single x 1 act x 1 sometimes x 1 curly brackets x 1 limit x 1 scope x 1 language x 1 uses x 1 evaluation x 1 assigned x 1 values x 1 To x 1 effect x 1 semicolon x 1 actions x 1 common x 1 consisting x 1 used x 1

var_dump instrucción var_dump simplemente muestra concordancia. Esta variante conserva expresiones de doble cita.

Para el archivo suministrado, este código finaliza en 0.047 segundos. Aunque el archivo más grande consumirá mucha memoria (debido a file función de file ).


C # code:

IEnumerable<KeyValuePair<String, Int32>> ProcessText(String text, int X, int Y) { // common words, that will be ignored var exclude = new string[] { "and", "is", "the", "as", "of", "to", "or", "in", "for", "by", "an", "be", "may", "has", "can", "its" }.ToDictionary(word => word); // regular expression to find quoted text var regex = new Regex("/"[^/"]/"", RegexOptions.Compiled); return // remove quoted text (it will be processed later) regex.Replace(text, "") // remove case dependency .ToLower() // split text by all these chars .Split(".,''///[]{}()`~@#$%^&*-=+?!;:<>| /n/r".ToCharArray()) // add quoted text .Concat(regex.Matches(text).Cast<Match>().Select(match => match.Value)) // group words by the word and count them .GroupBy(word => word, (word, words) => new KeyValuePair<String, Int32>(word, words.Count())) // apply filter(min word count and word length) and remove common words .Where(pair => pair.Value >= X && pair.Key.Length >= Y && !exclude.ContainsKey(pair.Key)); }

Salida para ProcessText (texto, 3, 2) llamada:

3 x languages 3 x such 4 x code 4 x which 3 x based 3 x each 4 x declarations 5 x function 4 x statements 3 x new 3 x types 3 x keywords 3 x variables 7 x statement 4 x expression 3 x execution 3 x programming 3 x operators


Cª#:

  1. Use LINQ, específicamente groupby, luego filtre por grupo y regrese una lista aplanada (seleccione many).

  2. Use LINQ, filtre por longitud.

  3. Use LINQ, filtre con ''badwords''. Contiene.


Esto no va a ganar ningún premio de golf, pero mantiene juntas las frases citadas y tiene en cuenta las palabras de pausa (y aprovecha los módulos de CPAN Lingua :: StopWords y Text :: ParseWords ).

Además, utilizo to_S de Lingua :: EN :: Inflect :: Number para contar solo las formas de palabras singulares.

También es posible que desee ver Lingua :: CollinsParser .

#!/usr/bin/perl use strict; use warnings; use Lingua::EN::Inflect::Number qw( to_S ); use Lingua::StopWords qw( getStopWords ); use Text::ParseWords; my $stop = getStopWords(''en''); my %words; while ( my $line = <> ) { chomp $line; next unless $line =~ //S/; next unless my @words = parse_line('' '', 1, $line); ++ $words{to_S $_} for grep { length and not $stop->{$_} } map { s!^[[:punct:]]+!!; s![[:punct:]]+/z!!; lc } @words; } print "=== only words appearing 4 or more times ===/n"; print "$_ : $words{$_}/n" for sort { $words{$b} <=> $words{$a} } grep { $words{$_} > 3 } keys %words; print "=== only words that are 12 characters or longer ===/n"; print "$_ : $words{$_}/n" for sort { $words{$b} <=> $words{$a} } grep { 11 < length } keys %words;

Salida:

=== only words appearing 4 or more times === statement : 11 function : 7 expression : 6 may : 5 code : 4 variable : 4 operator : 4 declaration : 4 c : 4 type : 4 === only words that are 12 characters or longer === reinitialization : 2 control-flow : 1 sequence point : 1 optimization : 1 curly brackets : 1 text-line-based : 1 non-structured : 1 column-based : 1 initialization : 1


Otra solución de Python, a 247 caracteres. El código real es una sola línea de línea de Python altamente denso de 134 caracteres que computa todo en una sola expresión.

x=3;y=2;W="and is the as of to or in for by an be may has can its".split() from itertools import groupby as gb d=dict((w,l)for w,l in((w,len(list(g)))for w,g in gb(sorted(open("c.txt").read().lower().split()))) if l>x and len(w)>y and w not in W)

Una versión mucho más larga con muchos comentarios para que disfrutes leyendo:

# High and low count boundaries. x = 3 y = 2 # Common words string split into a list by spaces. Words = "and is the as of to or in for by an be may has can its".split() # A special function that groups similar strings in a list into a # (string, grouper) pairs. Grouper is a generator of occurences (see below). from itertools import groupby # Reads the entire file, converts it to lower case and splits on whitespace # to create a list of words sortedWords = sorted(open("c.txt").read().lower().split()) # Using the groupby function, groups similar words together. # Since grouper is a generator of occurences we need to use len(list(grouper)) # to get the word count by first converting the generator to a list and then # getting the length of the list. wordCounts = ((word, len(list(grouper))) for word, grouper in groupby(sortedWords)) # Filters the words by number of occurences and common words using yet another # list comprehension. filteredWordCounts = ((word, count) for word, count in wordCounts if word not in Words and count > x and len(word) > y) # Creates a dictionary from the list of tuples. result = dict(filteredWordCounts) print result

El truco principal aquí es usar la función itertools.groupby para contar las ocurrencias en una lista ordenada. No sé si realmente guarda caracteres, pero permite que todo el procesamiento ocurra en una sola expresión.

Resultados:

{''function'': 4, ''operators'': 4, ''declarations'': 4, ''which'': 4, ''statement'': 5}


F # : 304 caracteres

let f = let bad = Set.of_seq ["and";"is";"the";"of";"are";"by";"it"] fun length occurrence msg -> System.Text.RegularExpressions.Regex.Split(msg, @"[^/w-'']+") |> Seq.countBy (fun a -> a) |> Seq.choose (fun (a, b) -> if a.Length > length && b > occurrence && (not <| bad.Contains a) then Some a else None)


Guiones de GNU

sed -e ''s/ //n/g'' | grep -v ''^ *$'' | sort | uniq -c | sort -nr

Resultados:

7 be 6 to [...] 1 2. 1 -

Con una ocurrencia mayor que X:

sed -e ''s/ //n/g'' | grep -v ''^ *$'' | sort | uniq -c | awk ''$1>X''

Devuelve solo palabras con una longitud mayor que Y (pon Y + 1 puntos en el segundo grep):

sed -e ''s/ //n/g'' | grep -v ''^ *$'' | grep .... | sort | uniq -c

Ignore términos comunes como "y, es, el, etc." (suponiendo que los términos comunes están en el archivo ''ignorado'')

sed -e ''s/ //n/g'' | grep -v ''^ *$'' | grep -vf ignored | sort | uniq -c

Siéntase libre de quitar la puntuación antes del procesamiento (es decir, "John''s" se convierte en "John"):

sed -e ''s/[,.:"/']//g;s/ //n/g'' | grep -v ''^ *$'' | sort | uniq -c

Devuelve resultados en una colección / matriz: ya es como una matriz para shell: la primera columna es el recuento, la segunda es la palabra.


Python (258 caracteres como están, incluidos 66 caracteres para la primera línea y 30 caracteres para la eliminación de la puntuación):

W="and is the as of to or in for by an be may has can its".split() x=3;y=2;d={} for l in open(''c.txt'') : for w in l.lower().translate(None,'',.;/'"!()[]{}'').split() : if w not in W: d[w]=d.get(w,0)+1 for w,n in d.items() : if n>y and len(w)>x : print n,w

salida:

4 code 3 keywords 3 languages 3 execution 3 each 3 language 4 expression 4 statements 3 variables 7 statement 5 function 4 operators 4 declarations 3 programming 4 which 3 such 3 types


#! perl use strict; use warnings; while (<>) { for my $word (split) { $words{$word}++; } } for my $word (keys %words) { print "$word occurred $words{$word} times."; }

Esa es la forma simple. Si desea clasificar, filtrar, etc.

while (<>) { for my $word (split) { $words{$word}++; } } for my $word (keys %words) { if ((length($word) >= $MINLEN) && ($words{$word) >= $MIN_OCCURRENCE) { print "$word occurred $words{$word} times."; } }

También puede ordenar la salida con bastante facilidad:

... for my $word (keys %words) { if ((length($word) >= $MINLEN) && ($words{$word) >= $MIN_OCCURRENCE) { push @output, "$word occurred $words{$word} times."; } } $re = qr/occurred (/d+) /; print sort { $a = $a =~ $re; $b = $b =~ $re; $a <=> $b } @output;

Un verdadero pirata informático de Perl los obtendrá fácilmente en una o dos líneas cada uno, pero yo busqué la legibilidad.


Editar: así es como volvería a escribir este último ejemplo

... for my $word ( sort { $words{$a} <=> $words{$b} } keys %words ){ next unless length($word) >= $MINLEN; last unless $words{$word) >= $MIN_OCCURRENCE; print "$word occurred $words{$word} times."; }

O si lo necesito para correr más rápido, incluso podría escribirlo así:

for my $word_data ( sort { $a->[1] <=> $b->[1] # numerical sort on count } grep { # remove values that are out of bounds length($_->[0]) >= $MINLEN && # word length $_->[1] >= $MIN_OCCURRENCE # count } map { # [ word, count ] [ $_, $words{$_} ] } keys %words ){ my( $word, $count ) = @$word_data; print "$word occurred $count times."; }

Utiliza el mapa para la eficiencia, grep para eliminar elementos adicionales y ordena para hacer la clasificación, por supuesto. (lo hace en ese orden)

Esta es una pequeña variante de la transformada de Schwartz .