Misture as palavras enquanto preserva seus contornos

44

Isso é muito mais avançado do que Como aleatoriamente letras em uma palavra e Transposição de Cambridge, devido à regra sobre quais letras podem ser trocadas por quais. Um regex simples não será suficiente aqui.


É sabido que um texto ainda pode ser lido enquanto as entranhas de suas palavras foram embaralhadas, desde que a primeira e a última letras e os contornos gerais permaneçam constantes. Dado um texto imprimível Ascii + Newline, embaralhe cada palavra de acordo com estas regras:

  1. O embaralhamento deve ser (pseudo) aleatório.

  2. Uma palavra é uma sequência de caracteres latinos, de A a Z.

  3. Somente as letras iniciais serão sempre em maiúsculas.

  4. A primeira e a última letras devem permanecer intocadas.

  5. Ao embaralhar, apenas as letras de um dos seguintes grupos podem trocar de lugar:

    1. acemnorsuvwxz

    2. bdfhkl

    3. gpqy

    4. it

    5. j (permanece no lugar)

Exemplo

Srcmable consome enquanto psrrnveieg seus oeiltnus

É sabido que um txet ainda pode ser lido enquanto as entradas de seus cabos foram alteradas, desde que suas primeiras letras e suas letras mais suas letras maiúsculas e minúsculas não possam. Dado um padrão Acsii + Nwnliee txet, samrclbe ecah word anoccdirg to relus:

  1. Smncrbliag deve ser (pusedo) rondam.

  2. Um wrod é uma sequência dos chreratacs latinos, A thurogh Z.

  3. Somente as primeiras empresas nunca serão atualizadas.

  4. As letras fisrt e lsat devem permanecer atualizadas.

  5. Ao confirmar, apenas as letras de um dos guiões da fwllnoiog podem trocar trocas:

    1. aneusvrowxmcz

    2. bhkfdl

    3. gqpy

    4. it

    5. j (permanece em plcae)

Emxaple

Adão
fonte
té suposto ser mais curto do que, hembora muitas pessoas não o escrevam.
Freira vazada
@LeakyNun eu sei, mas você sugere a remoção tdo grupo 2? Ou talvez colocar tum grupo 4 com i?
Adám
O último ficaria bem.
Freira vazando
o tempo de execução pode ser teoricamente ilimitado? (como tentativas aleatórias até que algo é certo)
Sarge Borsch
1
printable/ patnirlbenão é bem legível. Eu acho que o i/ tswap é o culpado. Hmm ... paintrlbeNão, isso também não ajudou. Provavelmente é o pr/ paswap, então. O esquema mantém, mas acho que li "pr" e "pa" como sendo semanticamente (?) 1 letra. prtnialbeAh sim. Isso foi o que aconteceu. Não tenho certeza se posso oferecer uma correção para o algoritmo.
Draco18s

Respostas:

9

Geléia , 80 74 bytes

-2 bytes movendo de czar + vex + mow + sunpara czar + vexes + unmown(os es e s repetidos nnão são um problema)
-1 byte usando em Tịvez de ȦÐf
-1 byte usando em Œle€Øavez de i@€ØB>⁵
-2 bytes reconfigurando um pouco o layout

Tị
TẊị⁹ż@œp
e€ç⁸F
W;“HọƊṘ€.`]HɲøƁḤ0ẉlfrøj⁷»Ḳ¤ç/
Ḣ,ṪjÇḟ0
Œle€Øað¬œpÇ€ÑżœpÑ¥

Um programa completo com uma lista de caracteres (ou string formatada em Python), que imprime o resultado da disputa.

Experimente online!

Parece que aqui há uma enorme dificuldade para Jelly (ou eu perdi um truque, o que é sabido que aconteceu!) Isso certamente será derrotado por idiomas com melhor manipulação de cordas como Retina (sem funcionalidade aleatória) ou 05ab1e .

Quão?

Tị - Link 1, get truthy items: list a
T  - truthy indexes of a
 ị - index into a

TẊị⁹ż@œp - Link 2, selective shuffle: list a, list b
T        - truthy indexes of a (those indexes that may be shuffled in b)
 Ẋ       - random shuffle
   ⁹     - link's right argument, b
  ị      - index into (gets the shuffled values)
      œp - partition b at truthy indexes of a
    ż@   - zip with reversed @rguments (place shuffled values - yields a list of lists)

e€ç⁸F - Link 3, value selective shuffle: list a, list b
e€    - c exists in b? for €ach c in a (1s where b has shuffle-able characters, else 0s)
   ⁸  - link's left argument, a
  ç   - call the last link (2) as a dyad
    F - flatten the result (from the yielded list of lists to one list)

W;“HọƊṘ€.`]HɲøƁḤ0ẉlfrøj⁷»Ḳ¤ç/ - Link 4, perform all shuffles on a word's innards: list x
W                             - wrap x in a list
                          ¤   - nilad followed by link(s) as a nilad:
  “HọƊṘ€.`]HɲøƁḤ0ẉlfrøj⁷»     -   compression of s(bdfhkl)+d( czar)+d(vexes)+d(unmown)+s( gpqy)+d( ti)
                              -     where d() looks up a word in Jelly's dictionary and s() adds a string to the compressed output.
                         Ḳ    -   split on spaces: ["bdfhkl","czarvexesunmown","gpqy","ti"]
                           ç/ - reduce by last link (3) as a dyad (shuffles by each in turn)

Ḣ,ṪjÇḟ0 - Link 5, shuffle a word: list w
Ḣ       - head w (yields the leftmost character and modifies w)
  Ṫ     - tail w (yields the rightmost character and modifies w)
 ,      - pair
        -   Note: head and tail yield 0 when w is empty, so ['a'] -> ["a",0] and [] -> [0,0]
    Ç   - call the last link (4) as a monad (with the modified w)
   j    - join
     ḟ0 - filter discard zeros (thus single or zero letter words pass through unchanged)

Œle€Øað¬œpÇ€ÑżœpÑ¥ - Main link: list s
Œl                 - convert s to lowercase, say t
    Øa             - lowercase alphabet, say a
  e€               - c exists in a? for €ach c in t
      ð            - dyadic chain separation (call that u)
       ¬           - not (vectorises across u), say v
        œp         - partition s at truthy indexes of v (extract words, plus empty lists from within strings of non-alphabetic characters)
          Ç€       - call the last link (5) as a monad for €ach (shuffle their innards)
            Ñ      - call the next link (1) as a monad (only keep the actual words)
                 ¥ - last two links as a dyad:
              œp   -   partition s at truthy indexes of u (get the non-words, plus empty lists from within strings of alphabetic characters)
                Ñ  -   call the next link (1) as a monad (only keep actual non-words)
             ż     - zip together
                   - implicit print
Jonathan Allan
fonte
Na verdade, é mais difícil do que eu pensava.
Freira vazando
@LeakyNun welp demorei muito mais do que 10 minutos para lidar com ele.
Jonathan Allan
1
@ JonathanAllan Sim, ele está lá há muito tempo e provavelmente fará parte do próximo lançamento, porque isso me incomodou muitas vezes.
Martin Ender
1
czar + vex + mow + sunAd
Adám
3
@ Adám pesquisas de dicionário para formar acemnorsuvwxz. Também escreverei o código comentado em algum momento.
Jonathan Allan
5

PHP, 278 bytes

<?=preg_replace_callback("#\pL\K(\pL+)(?=\pL)#",function($t){preg_match_all("#([^bdf-lpqty])|([bdfhkl])|([gpqy])|([it])|(j)#",$t[0],$p);foreach($p as$v){$k++?$c=array_keys($n=array_filter($v)):$o=[];!$n?:shuffle($n)&&$o+=array_combine($c,$n);}ksort($o);return join($o);},$argn);

Experimente online!

Expandido

echo preg_replace_callback("#\pL\K(\pL+)(?=\pL)#" # patter \pL is shorter as [a-z]
,function($t){  # replacement function beginning
  preg_match_all("#([^bdf-lpqty])|([bdfhkl])|([gpqy])|([it])|(j)#",$t[0],$p); # makes groups with the regex. group 0 is the whole substring
  foreach($p as$v){ # loop through groups
    $k++?$c=array_keys($n=array_filter($v)):$o=[]; # group 0 make new empty replacement array in the other case filter the group remove empty values. 
    #You gain an array with the keys as position in the substring and the values
    #store the key array and the values array
    !$n?:shuffle($n)&&$o+=array_combine($c,$n); 
    #if values shuffle the values and make a new array with the keys and the shuffled values and merge the new array to the replacement array
  }
  ksort($o); # sort the replacement array ascending positions 
  return join($o); # return the replacement as string
},$argn);

funções

array_combine

array_filter

array_keys

ksort

preg_replace_callback

embaralhar

Jörg Hülsermann
fonte
Dica: você pode usar a configuração "desativar o cache de saída" no TIO, em vez de executar o código algumas vezes. Eu apenas corri com o exemplo - Tudo de bom!
Jonathan Allan
@ JonathanAllan Obrigado pela dica com o cache. Foi difícil o suficiente para encontrar uma maneira de resolver isso
Jörg Hülsermann
5

Pitão , 79 bytes

sm?td++hduuXNhTeTC,f@@GTHUG.S@HGG+-GJ."by❤jã~léܺ"cJ\jPtdedd:jb.z"([A-Za-z]+)"3

onde é U + 0018.

Experimente online!

Amostra

É sabido que um texto ainda pode ser vasculhado enquanto as partes íntimas de seus escritos foram gravadas, desde que a primeira e a última letra, além de todas as outras informações sobre a conexão. Dado um texto, submeta cada acrncdiog de texto ao seguinte relus:

  1. Scamrlbing deve ser (puesdo) rnadom.

  2. Uma palavra é uma suqencee dos chraectars latinos, A thuorgh Z.

  3. Somente as letras letivas nunca serão melhoradas.

  4. A primeira e a última letra não foram exibidas.

  5. Ao planejar, apenas as letras com um dos seguintes guias podem usar as seguintes palavras:

    1. amsuvrcnoxewz

    2. bhfkdl

    3. gpqy

    4. it

    5. j (permanece no lugar)

Freira Furada
fonte
Você não pode salvar com em \pLvez de [A-Za-z]?
Adám
@ Adám O que é \pL?
Freira vazando
Qualquer personagem com o p roperty de ser um L etter.
Adám
Eu não acho que ele funciona aqui ...
Leaky Nun
não \wseria suficiente?
Sarge Borsch
5

JavaScript 176 bytes

t.replace(/\B(\w+)\B/g,b=>{return[/[acemnorsuvwxz]/g,/[bdfhkl]/g,/[gpqy]/g,/[it]/g].forEach(d=>{g=b.match(d),b=b.replace(d,c=>{return g.splice(Math.random()*g.length,1)})}),b})

Método:

  1. RegExp itera sobre o centro de cada palavra ( /\B(\w+)\B/g) usando 1st replace fn.

  2. 1º substituir fn itera uma matriz de RegExp para cada grupo de letras ( /[bdfkhl/g, /[gqpy]/g, etc..).

  3. Cada iteração cria uma matriz temporária de caracteres do centro de palavras que aparecem no grupo de letras atual.

  4. Cada iteração usa o RegExp do grupo de letras atual para iterar todo o centro de palavras, usando uma segunda substituição fn.

  5. 2º substituir fn emenda aleatoriamente a matriz temporária, removendo um caractere aleatório e retornando-o.

Demo:

Execute-o no JSFiddle: https://jsfiddle.net/CookieJon/bnpznb7r/

Irregular
fonte
Bem-vindo ao PPCG. Primeira resposta incrível. No entanto, eu acho que você precisa \pL(\pL+)\pL, em vez de \B(\w+)\Bexcluir dígitos e sublinhado.
Adám
Ah obrigada! Devo admitir que regex não é a minha bolsa (eu tenho que procurar a referência TODAS as vezes em que a uso!) Posso engolir os 3 caracteres extras ... atualizará minha resposta em breve, obrigado novamente. :-)
Bumpy
1
Primeira resposta incrível! :) Algumas melhorias rápidas para você reduzir para 155 bytes, incluindo a correção @ Adáms acima: t => t.replace (/ \ B [az] + \ B / gi, b => ([/ [acemnorsuvwxz ] / g, / [bdfhkl] / ‌ g, / [gpqy] / g, / [it] / g] ‌ .map (d => b = b.replace (‌ d, c => g. splice (new Date% g.length, 1), g = b.match (d))), b))
Salsicha
@ Shagy Acho que b=>[...].map(...)&&bsalva outro byte. Também não tenho certeza de que você ié necessário.
1111 Neil
Se o @ Adám for estritamente exigente com sua definição de palavras, será necessário usá-lo t.replace(/[A-Za-z]([a-z]+)(?=[a-z])/g,(w,b)=>...w[0]+b...)ou algo assim.
1111 Neil
2

C, 453, 356 369 bytes

#define F for
#define M rand()%s+1+q
char a[256],*b=" acemnorsuvwxz\1bdfhkl\1gpqy\1it\1j";g(c,t)char*c,*t;{static int i,j,k,w,v,n,q,s,r;r=-1;if(c&&t){strcpy(c,t);if(!k)F(j=i=k=1;b[i];++i)b[i]-1?(a[b[i]]=j):++j;F(r=i=0;c[i];){F(;isspace(c[i]);++i);F(q=i;!isspace(c[i])&&c[i];++i);F(s=v=i-q-2;--v>0;)if(a[c[j=M]]==a[c[w=M]]&&a[c[j]])n=c[j],c[j]=c[w],c[w]=n;}}return r;}

ungolf com comentários

// Input in the arg "t" result in the arg "c"
// NB the memory pointed from c has to be >= memory pointed from t
//    the char is 8 bit
#define F for
#define M rand()%s+1+q
char a[256], *b=" acemnorsuvwxz\1bdfhkl\1gpqy\1it\1j";
   g(c,t)char*c,*t;
   {static int i,j,k,w,v,n,q,s,r;
    r=-1;
    if(c&&t)
      {strcpy(c,t);                         // copy the string in the result space
       if(!k)
         F(j=i=k=1;b[i];++i)
             b[i]-1?(a[b[i]]=j):++j;        // ini [possible because at start k=0]
       F(r=i=0;c[i];)
         {F(;isspace(c[i]);++i);            //skip spaces
                                            // the start q the end+1 i
          F(q=i;!isspace(c[i])&&c[i];++i);  //skip word
          F(s=v=i-q-2;--v>0;)               //loop for swap letters of the same set
            if(a[c[j=M]]==a[c[w=M]]&&a[c[j]])
                n=c[j],c[j]=c[w],c[w]=n;
         }
      }
   return r;
  }


#include <stdio.h>
#define G(x,y) if(x)goto y
main()
{char a[256],r[256];
l1:
 gets(a);// i would know the string lenght<256
 g(r,a);
 printf("%s\n",r);
 G(*a,l1);
}
RosLuP
fonte
1

Python 3.6, 349 340 bytes

from itertools import *
from random import *
import re
def S(s):
    C=lambda c:len(list(takewhile(lambda x:c not in x,('j','it','gqpy','bhkfdl'))));L=[];B=[[]for i in range(5)]
    for l in s:c=C(l);L+=[c];B[c]+=[l];shuffle(B[c])
    return''.join(B[n].pop()for n in L)
A=lambda t:re.sub('[A-Za-z]{3,}',lambda x:x[0][0]+S(x[0][1:][:-1])+x[0][-1],t)

Recuado com guias. A função é nomeada A. Ele não usa força bruta, o tempo de execução é determinístico, como o OP pediu.

Sarge Borsch
fonte
1

Mathematica 232 Bytes

StringReplace[#,x:Repeated[WordCharacter,{2,∞}]:>""<>(s=StringTake)[x,{i,i}~Table~{i,StringLength@x}/.Flatten[Thread[#->RandomSample@#]&/@(StringPosition[x~s~{2,-2},#]+1&/@Characters@{"acemnorsuvwxz","bdfhkl","gpqy","it","j"})]]]&

A idéia básica é permutar os subconjuntos correspondentes aos 4 grupos de caracteres distintos. Provavelmente espaço para melhorias.

Kelly Lowder
fonte
1

C, 306 282 bytes

c,o,d,e,g;l(char*f){char*s[]={"aneusvrowxmcz","bhkfdl","gqpy","it",0},**h,*i,*t;for(i=f;*i;){if(isalpha(*i)){t=i;while(*i&&isalpha(*i))i++;e=i-t-2;for(h=s;*h&&e;*h++){for(c=999;--c;){d=1+rand()%e,o=1+rand()%e;if(strchr(*h,t[d])&&strchr(*h,t[o]))g=t[d],t[d]=t[o],t[o]=g;}}}else++i;}}

Experimente online

Ungolfed:

int func(char*p) 
{
    char *groups[] = {"aneusvrowxmcz","bhkfdl","gqpy","it",0}, **g, *s, *t;
    int n,r,i,l,o;

    for (s = p; *s;)
    {
        if (isalpha(*s))
        {
            t = s;
            while (*s && isalpha(*s))
                s++;
            // start scrambling
            l = s - t - 2;
            for(g=groups; *g && l; *g++)
            {
                for(n=999;--n;)
                {
                    i = 1 + rand() % l;
                    r = 1 + rand() % l;
                    if (strchr(*g, t[i]) && strchr(*g, t[r]))
                    {
                        o=t[i];
                        t[i]=t[r];
                        t[r]=o;
                    }
                }
            }
            // end scrambling
        }
        else 
            s++;
    }
}
Johan du Toit
fonte
Por que você gostaria de trocar 999 em uma palavra? Você sabe que uma palavra de um caractere tem l = -1 e isso possivelmente significa que ele começa a fazer 999 possíveis trocas usando 1 + rand ()% -1 para escrever aleatoriamente em 2 giga de memória ... Mas é possível que eu veja errado ....
RosLuP
Há, infelizmente, nenhuma mágica sobre o uso de 999. É apenas 1 byte inferior a 1000 :)
Johan du Toit
No gcc, parece rand ()% (- 1) retornar 0 nas 2 primeiras vezes que tentei. por isso possível, não troca de espaço 2giga aleatório ...% do int não é a% de sem assinatura ...
RosLuP
@RosLup, me desculpe, mas eu não sigo o que você está dizendo ..
Johan du Toit
1

JavaScript (ES6), 380 327 311 294 bytes

( 298 282 265 bytes, excluindo as regras)

Obrigado a @Shaggy pelas dicas úteis!

((b,d)=>b.replace(/\B[a-z]+\B/gi,f=>(g=>(g.map(j=>(h=d.slice(0,~(rind=d.indexOf(j))?rind:-1),~rind?h.split`,`.length-1:-1)).map((j,k,l,m=[])=>{l.map((n,o)=>n==j?m.push(o):0),sub=m[new Date%(m.length-1)]||k,tmp=g[sub],g[sub]=g[k],g[k]=tmp}),g.join``))([...f])))(s,"aneusvrowxmcz,bhkfdl,gqpy,it");

var f = ((b,d)=>b.replace(/\B[a-z]+\B/gi,f=>(g=>(g.map(j=>(h=d.slice(0,~(rind=d.indexOf(j))?rind:-1),~rind?h.split`,`.length-1:-1)).map((j,k,l,m=[])=>{l.map((n,o)=>n==j?m.push(o):0),sub=m[new Date%(m.length-1)]||k,tmp=g[sub],g[sub]=g[k],g[k]=tmp}),g.join``))([...f])))

var s="Let there be scrambling";
console.log(s);
console.log(f(s,"aneusvrowxmcz,bhkfdl,gqpy,it"))

s="It is well known that a text can still be read while the innards of its words have been scrambled, as long as their first and last letters plus their overall outlines remain constant. Given a printable Ascii+Newline text, scramble each word according to these rules";
console.log(s);
console.log(f(s,"aneusvrowxmcz,bhkfdl,gqpy,it"))

A função f recebe uma sequência de qualquer tipo (palavra única, várias palavras, várias palavras com sinais - que ela interpreta como quebra de palavras) e uma matriz de uma sequência de "regras" de qualquer tamanho, separadas por vírgulas.

Esse conjunto de regras, no caso de sua pergunta, seria ["aneusvrowxmcz", "bhkfdl", "gqpy", "it"] "aneusvrowxmcz,bhkfdl,gqpy,it"

Algumas letras não se misturam, mesmo que pudessem, pois você afirmou na sua pergunta que as letras "podem trocar espaços". Se o interpretei errado, posso alterar o código para sempre embaralhar as letras que correspondem às regras.

Eu sei que é uma quantidade enorme de bytes e não será capaz de competir com idiomas de golfe, mas eu queria tentar mesmo assim, espero que gostem :)

Código não uglificado legível por humanos:

((txt,rules)=>txt.replace(/\B[a-z]+\B/gi,wo=>((w=>(w.map(c=>(h=rules.slice(0, ~(rind=rules.indexOf(c))?rind:-1),~rind?(h.split`,`.length-1):-1)).map((e,i,arr,a=[])=>{
    arr.map((x,i)=>(x==e)?a.push(i):0),
    sub=a[new Date%(a.length-1)]||i,
    tmp=w[sub],
    w[sub]=w[i],
    w[i]=tmp
}),w.join``))([...wo]))))(str, "aneusvrowxmcz,bhkfdl,gqpy,it")
Hankrecords
fonte
1
As regras do OP devem ser incluídas na contagem de bytes. Em maio , eu quis dizer ter uma chance .
Adám
1
Bem-vindo ao PPCG :) Você pode definitivamente jogar muito fora disso.
Shaggy
1
Eu estava tentando jogar golfe para você, mas, dado o quanto se pode fazer com ele, o tempo acabou e, em vez disso, aponto aqui e aqui para ajudar você a começar.
Shaggy
1
Algumas dicas rápidas, porém: 01) Livrar-se de todo o vars uma lets. 02) A menos que seja uma função recursiva, não é necessário incluir a declaração de variável ( f=) na sua contagem de bytes. 03) Use currying quando uma função tiver 2 parâmetros (em b=>d=>vez de (b,d)=>) e chame sua função com f(b)(d). 04) Você tem a ibandeira, portanto não há necessidade de incluir A-Zno seu regex. 05) Você pode usar indexOfou searchem uma string, sem dividi-la em uma matriz.
Shaggy
1
Como a sugestão 03 salva caracteres? Eles têm a mesma aparência para mim.
Steve Bennett
0

Clojure, 326 322 324 bytes

Atualização 1: substituída (map(fn[[k v]]...)...)por(for[[k v]...]...)

Atualização 2: regex fixo, usando em \pLvez de \wetc.

#(let[G(zipmap"bdfhklgpqyitj""0000001111223")](apply str(flatten(interleave(for[v(re-seq #"\pL+"%)w[(rest(butlast v))]W[(into{}(for[[k v](group-by G w)][k(shuffle v)]))]R[(rest(reductions(fn[r i](merge-with + r{(G i)1})){}w))]][(first v)(map(fn[c r](nth(W(G c))(-(r(G c))1)))w R)(if(second v)(last v))])(re-seq #"\PL+"%)))))

Estou ansioso para ver algo mais curto. A versão anterior não destruída, com alguns exemplos de execuções:

(def f #(let[G(zipmap"bdfhklgpqyitj""0000001111223")] ; Create groups, the longest "acemnorsuvwxz" goes to an implicit group nil
          (apply str(flatten(interleave
                              (for[v (re-seq #"\w+"%)                                          ; Iterate over words
                                   w [(rest(butlast v))]                                       ; This holds the middle part
                                   W [(into{}(map(fn[[k v]][k(shuffle v)])(group-by G w)))]    ; Create shuffled groups
                                   R [(rest(reductions(fn[r i](merge-with + r{(G i)1})){}w))]] ; Calculate cumulative sum of group items, used to look-up nth value from shuffled values
                               [(first v)                                     ; First character
                                (map(fn[g r](nth(W g)(-(r g)1)))(map G w)R)   ; Shuffled middle part
                                (if(>(count v)1)(last v))])                   ; Last character, unless the word is just a single character
                              (re-seq #"\W+"%)))))) ; Interleave with spaces, commas, newline etc.

(f "It is well known that a text can still be read while the innards of its words have been scrambled, as long as their first and last letters plus their overall outlines remain constant.\n")
;  "It is well known that a txet can sitll be read wlihe the irnands of its wrods hvae been seacmlbrd, as lnog as their fisrt and lsat letters plus their oavrell ontlieus rmaein cnontast.\n"
;  "It is well kwonn that a text can sitll be raed wlihe the innards of its wrods hvae been seramlbcd, as long as their fisrt and lsat lettres plus their oravell ouiltnes rmeain cnsatont.\n"
;  "It is well konwn that a text can still be read while the iarnnds of its words have been sraemlbcd, as lnog as their first and lsat lrttees plus their oaevrll ontlieus remain canntsot.\n"
NikoNyrh
fonte
Acho que você precisa \pL+e \PL+, em vez de \w+e \W+para excluir dígitos e sublinhado.
Adám
0

Perl 6 , 241 195 bytes

Inclui +1 byte para -pa opção de linha de comando.

s:g/(<:L>)(<:L>+)(<:L>)/{$0}{[~]
$1.comb.pairs.classify({first
.value~~*,:k,/<[bdfhkl]>/,/<[gpqy]>/,/<[it]>/,/j/,!0}).values.map({$_».key
»=>«$_».value.pick(*)})».List.flat.sort».value}$2/;

Ungolfed:

s:g/(<:L>)(<:L>+)(<:L>)/{$0}{
    [~]
    $1.comb
    .pairs
    .classify({
        first .value ~~ *, :k,
            /<[bdfhkl]>/,
            /<[gpqy]>/,
            /<[it]>/,
            /j/,
            !0
    })
    .values
    .map({ $_».key »=>« $_».value.pick(*) })
    ».List
    .flat
    .sort
    ».value
}$2/;
Sean
fonte
Eu acho que você precisa, em (\pL)(\pL+)(\pL)vez de (\w)(\w+)(\w)excluir dígitos e sublinhado.
Adám
Na verdade, \pLinclui muitos caracteres fora do intervalo permitido de letras latinas AZ. Atualizei meu código para refletir os requisitos com mais precisão.
21417 Sean
Quais personagens? Lembre-se de que a entrada é restrita a novas linhas ASCII + imprimíveis.
Adám
Ah, eu senti falta disso. \pLé escrito <:L>no Perl 6.
21417 Sean
0

C #, 438 394 380 374 bytes

namespace System.Text.RegularExpressions{using Linq;s=>Regex.Replace(s,@"\p{L}(([gpqy])|(i|t)|(j)|([bdf-l])|([a-z]))*?[a-z]?\b",m=>{var a=m.Value.ToArray();for(int i=1,j;++i<7;){var c=m.Groups[i].Captures;var n=c.Cast<Capture>().Select(p=>p.Index-m.Index).ToList();foreach(Capture p in c){a[j=n[new Random().Next(n.Count)]]=p.Value[0];n.Remove(j);}}return new string(a);});}

Economize 10 bytes graças a @ MartinEnder ♦.

Irritantemente, CaptureCollectionnão implementaIEnumerable<T> e é por isso que .Cast<Capture>()é necessário. Felizmente, eu posso combinar a consulta Linq e o foreachloop.

Tenho certeza de que muita coisa pode ser jogada no golfe, mas demorei o suficiente para fazê-la funcionar ...

Experimente online!

Versão formatada / completa:

namespace System.Text.RegularExpressions
{
    using Linq;

    class P
    {
        static void Main()
        {
            Func<string, string> f = s =>
                Regex.Replace(s, @"\p{L}(([gpqy])|(i|t)|(j)|([bdf-l])|([a-z]))*?[a-z]?\b", m =>
                {
                    var a = m.Value.ToArray();

                    for (int i = 1, j; ++i < 7;)
                    {
                        var c = m.Groups[i].Captures;

                        var n = c.Cast<Capture>().Select(p => p.Index - m.Index).ToList();

                        foreach(Capture p in c)
                        {
                            a[j = n[new Random().Next(n.Count)]] = p.Value[0];
                            n.Remove(j);
                        }
                    }

                    return new string(a);
                });

            Console.WriteLine(f("Scramble words while preserving their outlines"));
            Console.ReadLine();
        }
    }
}
TheLethalCoder
fonte