Подтвердить что ты не робот

Code golf: "Цветная подсветка" повторяющегося текста

(Спасибо greg0ire ниже за помощь в ключевых концепциях)

Задача: Создайте программу, которая находит все подстроки и "тегирует" их с атрибутами цвета (эффективно выделяя их в XML).

Правила:

  • Это нужно делать только для подстрок длиной 2 или более.
  • Подстроки - это просто строки последовательных символов, которые могут включать неалфавитные символы. Обратите внимание, что пробелы и другие знаки пунктуации не ограничивают подстроки.
  • Символьный корпус нельзя игнорировать.
  • "Выделение" должно выполняться путем пометки подстроки в XML. Ваша маркировка должна иметь вид <TAG#>theSubstring</TAG#>, где # - это положительное число, уникальное для этой подстроки и одинаковых подстрок.
  • Приоритет алгоритма состоит в том, чтобы найти самую длинную подстроку, а не сколько раз она совпадает с текстом.

Примечание. Порядок пометки, показанный в приведенном ниже примере, не важен. Его просто используется OP для ясности.


Пример ввода:

LoremIpsumissimplydummytextoftheprintingandtypesettingindustry.LoremIpsumhasbeentheindustry'sstandarddummytexteversincethe1500s,whenanunknownprintertookagalleyoftypeandscrambledittomakeatypespecimenbook.

Частично правильный выход (OP не может полностью полностью заменить в этом примере)

<TAG1>LoremIpsum</TAG1>issimply<TAG2>dummytext</TAG2>of<TAG5>the</TAG5><TAG3>print</TAG3>ingand<TAG4>type</TAG4>setting<TAG6>industry</TAG6>.<TAG1>LoremIpsum</TAG1>hasbeen<TAG5>the</TAG5><TAG6>industry</TAG6>'sstandard<TAG2>dummytext</TAG2>eversince<TAG5>the</TAG5>1500s,whenanunknown<TAG3>print</TAG3>ertookagalleyof<TAG4>type</TAG4>andscrambledittomakea<TAG4>type</TAG4>specimenbook.

Ваш код должен иметь возможность обрабатывать крайние случаи, например:

Пример ввода 2:

hello!TAG!</hello.TAG.</

Пример 2:

<TAG1>hello</TAG1>!<TAG2>TAG</TAG2>!<TAG3></</TAG3><TAG1>hello</TAG1>.<TAG2>TAG</TAG2>.<TAG3></</TAG3>

Победитель:

  • Самое элегантное решение выигрывает (судя по другие комментарии, upvotes)
  • Bonus точки/рассмотрение решений использование сценариев оболочки

Незначительные разъяснения:

  • Вход может быть жестко закодирован или прочитан из файла
  • Критерии остаются "элегантностью", которая, по общему признанию, немного расплывчата, но также включает в себя простое количество символов и строк. Комментарии других и/или upvotes также указывают на то, как сообщество SO рассматривает проблему.
4b9b3361

Ответ 1

Perl 206, 189, 188, 199, 157 символов

исключая оригинальная строка и последняя печать.
 #New algorithm that produces correct ouputs for many cases



    [email protected],q/LoremIpsumissimplydummytextoftheprintingandtypesettingindustry.LoremIpsumhasbeentheindustry'sstandarddummytexteversincethe1500s,whenanunknownprintertookagalleyoftypeandscrambledittomakeatypespecimenbook/;

    [email protected],q/oktooktobookokm/;
    [email protected],q!dino1</dino2</!;
    [email protected],q!dino1TAG2dino3TAG!;

    ## loop for tests doesn't count
    for $z(@z) {
    print "input : $z\n";
    $i=0;@r=();
    #### begin count
    $c=127;$l=length($_=$z);while($l>1){if(/(.{$l}).*\1/){[email protected],$1;++$c;s/$1/chr($c)/eg}else{$l--}}$z=$_;map{++$i;$x=chr(127+$i);$z=~s:$x:<TAG$i>$_</TAG$i>:g}@r
    #### end count 157 chars
    ## output doesn't count
    ;print "output : $z\n","="x80,"\n"
    }

__END__
perl tags2.pl
input : LoremIpsumissimplydummytextoftheprintingandtypesettingindustry.LoremIpsumhasbeentheindustry'sstandarddummytexteversincethe15
00s,whenanunknownprintertookagalleyoftypeandscrambledittomakeatypespecimenbook

output : <TAG1>LoremIpsum</TAG1>i<TAG11>ss</TAG11><TAG12>im</TAG12>ply<TAG2>dummytext</TAG2><TAG6>oft</TAG6><TAG13>he</TAG13><TAG4>p
rint</TAG4><TAG7>ing</TAG7><TAG8>and</TAG8><TAG5>types</TAG5>e<TAG14>tt</TAG14><TAG7>ing</TAG7><TAG3>industry</TAG3>.<TAG1>LoremIpsu
m</TAG1>hasbe<TAG15>en</TAG15><TAG9>the</TAG9><TAG3>industry</TAG3>'<TAG11>ss</TAG11>t<TAG8>and</TAG8>ard<TAG2>dummytext</TAG2>ev<TA
G16>er</TAG16>since<TAG9>the</TAG9>1500s,w<TAG13>he</TAG13>nanunknown<TAG4>print</TAG4><TAG16>er</TAG16>t<TAG10>ook</TAG10>agal<TAG1
7>le</TAG17>y<TAG6>oft</TAG6>y<TAG18>pe</TAG18><TAG8>and</TAG8>scramb<TAG17>le</TAG17>di<TAG14>tt</TAG14>omakea<TAG5>types</TAG5><TA
G18>pe</TAG18>c<TAG12>im</TAG12><TAG15>en</TAG15>b<TAG10>ook</TAG10>
================================================================================
input : oktooktobookokm
output : <TAG1>okto</TAG1><TAG1>okto</TAG1>bo<TAG2>ok</TAG2><TAG2>ok</TAG2>m
================================================================================
input : dino1</dino2</
output : <TAG1>dino</TAG1>1<TAG2></</TAG2><TAG1>dino</TAG1>2<TAG2></</TAG2>
================================================================================
input : dino1TAG2dino3TAG
output : <TAG1>dino</TAG1>1<TAG2>TAG</TAG2>2<TAG1>dino</TAG1>3<TAG2>TAG</TAG2>
================================================================================

Ответ 2

Python, 236 206 символов

s="LoremIpsumissimplydummytextoftheprintingandtypesettingindustry.LoremIpsumhasbeentheindustry'sstandarddummytexteversincethe1500s,whenanunknownprintertookagalleyoftypeandscrambledittomakeatypespecimenbook."
### ------------------------------------------------------------
import re
c=o=127
l={}
i=len(s)/2
while i>1:
    r=re.search('(.{%d}).*\\1'%i,s)
    if r:f=r.group(1);c+=1;l[c-o]=f;s=s.replace(f,chr(c))
    else:i-=1
for i in l:s=re.sub(chr(i+o),'<TAG%d>%s</TAG%d>'%(i,l[i],i),s)
### ------------------------------------------------------------
print s

И в результате выполнения этого на примере ввода он выбирает следующие слова ( "LoremIpsum", "dummytext", "industry", "print", "types", "oft", "ing", и ',' ',' ook ',' ss ',' im ',' he ',' tt ',' en ',' er ',' le ',' pe '), и результат:

<TAG1>LoremIpsum</TAG1>i<TAG11>ss</TAG11><TAG12>im</TAG12>ply<TAG2>dummytext</TAG2><TAG6>oft</TAG6><TAG13>he</TAG13><TAG4>print</TAG4><TAG7>ing</TAG7><TAG8>and</TAG8><TAG5>types</TAG5>e<TAG14>tt</TAG14><TAG7>ing</TAG7><TAG3>industry</TAG3>.<TAG1>LoremIpsum</TAG1>hasbe<TAG15>en</TAG15><TAG9>the</TAG9><TAG3>industry</TAG3>'<TAG11>ss</TAG11>t<TAG8>and</TAG8>ard<TAG2>dummytext</TAG2>ev<TAG16>er</TAG16>since<TAG9>the</TAG9>1500s,w<TAG13>he</TAG13>nanunknown<TAG4>print</TAG4><TAG16>er</TAG16>t<TAG10>ook</TAG10>agal<TAG17>le</TAG17>y<TAG6>oft</TAG6>y<TAG18>pe</TAG18><TAG8>and</TAG8>scramb<TAG17>le</TAG17>di<TAG14>tt</TAG14>omakea<TAG5>types</TAG5><TAG18>pe</TAG18>c<TAG12>im</TAG12><TAG15>en</TAG15>b<TAG10>ook</TAG10>.

Что более читаемо в этой вики, выделенной следующим образом:

LoremIpsum я ss im слойные dummytext oft he print ing and types е tt ing industry. LoremIpsum hasbe en the industry 'ss т and ARD dummytext эв er так the 1500s, ш he nanunknown print er т ook AGAL le у oft у pe and scramb le ди tt omakea types pe с im en б ook.

PS. Кто-то жаловался, поэтому я добавил инструкции ввода и вывода. К запутанному я извиняюсь - мне это показалось очевидным. По-видимому, нет, поэтому я добавил инструкции префикса/трейлера, которые не требуются спецификацией проблемы и не должны учитываться длиной кода.

Ответ 3

Haskell: 343/344 403 420 445 485 символы

Число символов составляет 343 при использовании экспоненциального алгоритма, тогда как при использовании квадратичного алгоритма оно составляет 344.

Выведенный код является квадратичным. Для экспоненциального алгоритма измените одно вхождение inits=<<tails на subsequences в коде.

import Data.List
l=length
e=map$either id id
(&)=stripPrefix
[email protected](_:w)!x=l x>1&&maybe(w!x)(isInfixOf x)(x&y)
_!_=0<0
[email protected](x,i)[email protected](y:z)=maybe(y:t?z)(((map Right$'<':v++e x++"</"++v)++).(t?))$x&s where v="TAG"++i++">"
_?_=[]
r s=e$foldr(?)s$zip(sortBy(\a b->compare(l a)$l b)$filter(s!)$inits=<<tails s)$map show[1..]
main=getLine>>=putStr.r.map Left

Вход 1:

LoremIpsumissimplydummytextoftheprintingandtypesettingindustry.LoremIpsumhasbeentheindustry'sstandarddummytexteversincethe1500s,whenanunknownprintertookagalleyoftypeandscrambledittomakeatypespecimenbook.

Выход 1:

<TAG338>LoremIpsum</TAG338>i<TAG72>ss</TAG72><TAG122>im</TAG122>ply<TAG336>dummytext</TAG336><TAG188>oft</TAG188><TAG91>he</TAG91><TAG275>print</TAG275><TAG153>ing</TAG153><TAG191>and</TAG191><TAG276>types</TAG276><TAG88>et</TAG88><TAG214>ting</TAG214><TAG328>industry</TAG328>.<TAG338>LoremIpsum</TAG338>hasbe<TAG123>en</TAG123><TAG183>the</TAG183><TAG328>industry</TAG328>'s<TAG73>st</TAG73><TAG191>and</TAG191>ard<TAG336>dummytext</TAG336>ev<TAG99>er</TAG99>s<TAG96>in</TAG96>ce<TAG183>the</TAG183>1500s,wh<TAG123>en</TAG123><TAG111>an</TAG111>unknown<TAG275>print</TAG275><TAG99>er</TAG99>t<TAG195>ook</TAG195>a<TAG103>ga</TAG103>l<TAG113>le</TAG113>y<TAG105>of</TAG105><TAG241>type</TAG241><TAG191>and</TAG191>scramb<TAG113>le</TAG113>dit<TAG115>to</TAG115>mak<TAG116>ea</TAG116><TAG276>types</TAG276><TAG121>pe</TAG121>c<TAG122>im</TAG122><TAG123>en</TAG123>b<TAG195>ook</TAG195>.

Вход 2:

hello!TAG!</hello.TAG.</

Выход 2:

<TAG28>hello</TAG28>!<TAG22>TAG</TAG22>!<TAG14></</TAG14><TAG28>hello</TAG28>.<TAG22>TAG</TAG22>.<TAG14></</TAG14>

Ответ 4

Я думаю, вы можете использовать обратные ссылки для этого. См. Это сообщение: Регулярное выражение для обнаружения повторения внутри строки Я сделал много попыток, и на данный момент у меня есть это выражение: # ([a-zA-Z] +). *\1 #, но я думаю, что он находит первую повторяющуюся строку, а не самую большую...дель > Это было до того, как я понял, что тебя не волнуют слова... Что вам нужно сделать:

  • найти наибольшую последовательность символов, повторяющихся в тексте
  • удалите его из текста, где он отображается
  • повторять, пока вы не найдете ничего повторяющегося
  • использовать метод для раскрашивания строк, которые вы запомнили.

этот шаг описан на этой странице: http://en.wikipedia.org/wiki/Longest_common_substring_problem И вот реализация php: http://www.davidtavarez.com/archives/longer-common-substring-problem-php-implementation/ (вам нужно исправить это, оно содержит html-сущности, а комментарий говорит, что он возвращает целое число, но мы не знаем, что он представляет...), если он все еще не работает, вы можете попытаться реализовать псевдокод wikipedia.

Ответ 5

Python, 236 281 символ, нет REGEX:)

Делает набор M всех 2 + символьных строк, а затем итерации через них, чтобы назначить их в порядке жадной длины

s="LoremIpsumissimplydummytextoftheprintingandtypesettingindustry.LoremIpsumhasbeentheindustry'sstandarddummytexteversincethe1500s,whenanunknownprintertookagalleyoftypeandscrambledittomakeatypespecimenbook."
#s="abcd1TAGabcd2TAG"

### ----
L,C,R=len,chr,range
M,l,T,t=set(),L(s),[],0
[[M.add(s[A:B])for B in R(A+2,l)]for A in R(l)]
while 1:
 m,t=sorted([(L(m),m)if s.count(m)>1 else(0,"")for m in M])[-1][1],t+1
 if m=="":break
 T+=[(t,m)]
 s=s.replace(m,C(t))
for(t,m)in T:
 s=s.replace(C(t),"<TAG%d>%s</TAG%d>"%(t,m,t))
### ----

print s

Выходы, как и ожидалось:

<TAG1>LoremIpsum</TAG1>i<TAG11>ss</TAG11><TAG15>im</TAG15>ply<TAG2>dummytext</TAG2><TAG13>of</TAG13><TAG6>the</TAG6><TAG5>print</TAG5><TAG8>ing</TAG8><TAG9>and</TAG9><TAG4>types</TAG4>e<TAG10>tt</TAG10><TAG8>ing</TAG8><TAG3>industry</TAG3>.<TAG1>LoremIpsum</TAG1>hasbe<TAG17>en</TAG17><TAG6>the</TAG6><TAG3>industry</TAG3>'<TAG11>ss</TAG11>t<TAG9>and</TAG9>ard<TAG2>dummytext</TAG2>ev<TAG16>er</TAG16>since<TAG6>the</TAG6>1500s,wh<TAG17>en</TAG17>anunknown<TAG5>print</TAG5><TAG16>er</TAG16>t<TAG7>ook</TAG7>agal<TAG14>le</TAG14>y<TAG13>of</TAG13>ty<TAG12>pe</TAG12><TAG9>and</TAG9>scramb<TAG14>le</TAG14>di<TAG10>tt</TAG10>omakea<TAG4>types</TAG4><TAG12>pe</TAG12>c<TAG15>im</TAG15><TAG17>en</TAG17>b<TAG7>ook</TAG7>.

Ответ 6

Mathematica - 262 Chars

Не чистый функциональный/Не короткий/Не хорошо/Много побочных эффектов /

b = "LoremIpsumissimplydummytextoftheprintingandtypesettingindustry.\
     LoremIpsumhasbeentheindustry'sstandarddummytexteversincethe1500s,\
     whenanunknownprintertookagalleyoftypeandscrambledittomakeatypespecimen\
     book."

i = 0
a = c = "@"
v = [email protected]## &
w = [email protected]## &
t = x__ ~~ y__ ~~ __ ~~ x__ ~~ y__ /; v[x <> y, c]
NestWhile[
  w[#, (a = SortBy[StringCases[#, t -> x <> y,Overlaps -> True], [email protected]# &][[1]]) -> c] &,
  b,
  (z = [email protected]++i; b = w[b, a -> "<TAG" <> z <> ">" <> a <> "</TAG" <> z <> ">"] /. k -> IntegerString; True) && ! v[#, t] &]

Ответ 7

Большое спасибо Деннису Уильямсону, который помог мне прийти к такому подходу, ответив на несколько связанных вопросов, которые у меня были на сценариях оболочки - здесь и здесь.

Известные проблемы с ниже:

  • Он работает только для файлов ascii, а не для двоичных
  • Он работает только в том случае, если в файле нет новых строк.
  • Он длится экспоненциально дольше, поскольку файл становится длиннее
  • Он легко разбивается на файлы длиной более нескольких килобайт (заканчивается дисковое пространство tmp)

Как вы можете видеть, его огромный метод грубой силы - вовсе не умный алгоритм. Я записал время, затраченное на несколько образцов файлов.

bytes  time(s)
204 1.281
407 24.916
610 269.302

То же самое можно сказать и о том, что я делал это, как о том, что я делал это ниже. Это было для меня "мысль-вызов" - сделать это в среде оболочки и в максимально возможной степени. Больше ничего. Конечно, как показывают результаты, он крайне неэффективен, поэтому он совершенно не подходит для реального применения в мире.

filesize=`stat -c %s $1`
while [ $filesize -gt 1 ]
do
        filesize=`expr $filesize - 1`
        array=( "${array[@]}" $(cat $1 | sed -n ":a;/^.\{$filesize\}$/{p;b};s/.\{$filesize\}/&\n/;P;s/.//;s/\n//;ba" | sort | uniq -c | grep -v '      1' | cut -c9-) )
done

sample=$(<$1)
tag=0;
for entry in ${array[@]};
        do
        test="<[^>/]*>[^>]*$entry[^<]*</";
        if [[ ! $sample =~ $test ]];
                then ((tag++));
                sample=${sample//${entry}/<T$tag>$entry</T$tag>};
        fi;
        done;
echo $sample

Использование будет таким:

sh tagwords4 sample2.txt