Localizar correspondência de caso substituir

14

Pegue três entradas, uma sequência de texto T; uma sequência de caracteres para substituir F; e uma sequência de caracteres para substituí-los por R,. Para cada substring Tcom os mesmos caracteres (sem distinção entre maiúsculas e minúsculas) F, substitua-os pelos caracteres em R. No entanto, mantenha o mesmo caso que o texto original.

Se houver mais caracteres do Rque F, os caracteres extras deverão ser os mesmos que estão R. Se houver números ou símbolos F, os caracteres correspondentes Rdeverão manter o caso em que estão R. Fnão aparecerá necessariamente em T.

Você pode assumir que todo o texto estará no intervalo ASCII imprimível.

Exemplos

"Text input", "text", "test" -> "Test input"

"tHiS Is a PiEcE oF tExT", "is", "abcde" -> "tHaBcde Abcde a PiEcE oF tExT"

"The birch canoe slid on the smooth planks", "o", " OH MY " -> "The birch can OH MY e slid  OH MY n the sm OH MY  OH MY th planks"

"The score was 10 to 5", "10", "tEn" -> "The score was tEn to 5"

"I wrote my code in Brain$#@!", "$#@!", "Friend" -> "I wrote my code in BrainFriend"

"This challenge was created by Andrew Piliser", "Andrew Piliser", "Martin Ender" -> "This challenge was created by Martin Ender"

// Has a match, but does not match case 
"John does not know", "John Doe", "Jane Doe" -> "Jane does not know"

// No match
"Glue the sheet to the dark blue background", "Glue the sheet to the dark-blue background", "foo" -> "Glue the sheet to the dark blue background"

// Only take full matches
"aaa", "aa", "b" -> "ba"

// Apply matching once across the string as a whole, do not iterate on replaced text
"aaaa", "aa", "a" -> "aa"

"TeXT input", "text", "test" -> "TeST input"

Link sandbox

Andrew
fonte
Solicitando um exemplo com invólucro estranho:"TeXT input", "text", "test"
Engineer Toast
@EngineerToast Exemplo adicionado
Andrew
Sem saber por que achei "The birch canoe slid on the smooth planks", "o", " OH MY "tão engraçado, mas adorei esse exemplo.
Magic Octopus Urn

Respostas:

3

Retina , 116 bytes

i`(.+)(?=.*¶\1(¶.*)$)|.*¶.*$
¶¶$2¶$1¶¶
{T`l`L`¶¶.(?=.*¶[A-Z])
T`L`l`¶¶.(?=.*¶[a-z])
}`¶¶¶(.)(.*¶).
$1¶¶¶$2
¶¶¶¶.*|¶

Experimente online! Explicação:

i`(.+)(?=.*¶\1(¶.*)$)|.*¶.*$
¶¶$2¶$1¶¶

Ele pesquisa Te sempre que há uma correspondência que não diferencia maiúsculas de minúsculas do cabeçote de pesquisa para Fo fósforo, há um monte de novas linhas e o cabeçote de pesquisa Rtambém é inserido.

{T`l`L`¶¶.(?=.*¶[A-Z])
T`L`l`¶¶.(?=.*¶[a-z])
}`¶¶¶(.)(.*¶).
$1¶¶¶$2

Cada letra da cópia de Ré ajustada para corresponder à da correspondência, após o que é movida para fora da área de trabalho para que a próxima letra possa ser processada, até que a cópia Rou a correspondência fique sem letras.

¶¶¶¶.*|¶

Se a cópia Rficar sem letras, o restante da partida será precedido por 4 novas linhas, portanto, exclua-a. Caso contrário, tudo o que sobrar será deixado sobras de cópias Rque precisam ser concatenadas com as partes não correspondentes da entrada para produzir o resultado.

Neil
fonte
3

APL (Dyalog) , 75 73 72 bytes

Instruções para T, Re Fem que ordem. Rdeve ser fornecido no formato de transformação Dyalog e Fdeve ser fornecido no formato PCRE.

⍞⎕R(⍞∘{(⊣⌿d)l¨⍨(1∘⌷≠(⊢⌿d∊⎕A,lA)∧≠⌿)d≠(l819⌶)d←↑⍺⍵.Match↑¨⍨≢⍺})⍠1⊢⍞

Experimente online!

 solicitar T

 rendimento que (separa 1 e T)

⍞⎕R(... )⍠1 solicitar Fe R partidas EColoque com o resultado da seguinte função:

⍞∘{…} derivar uma função monádica, vinculando o Rargumento solicitado como à esquerda a:

  ≢⍺ conte o número de letras em R

  ⍺⍵.Match↑¨⍨ pegue tantas letras de cada uma Re a partida
   é o argumento da esquerda, que empatamos Rcomo.
   é um espaço para nome no qual Matchcontém a sequência encontrada no momento.

   misture os dois em uma matriz de duas linhas

  d← armazenar como d

  ()  Aplique a seguinte função tácita a isso:

   819⌶ minúsculas (mnemônico: 819 parece grande )

   l← armazenar essa função como l

  d≠ Booleano onde dé diferente (ou seja, dá 0/1 para cada letra minúscula / maiúscula)

  () Aplique a seguinte função tácita a isso:

   ≠⌿ XOR vertical

   ()∧ Booleano AND com a seguinte matriz:

    l⎕A lowercased Um lphabet

    ⎕A,Anexar um alfabeto l  maiúsculo

    d∊ Booleano para cada letra em d se um membro dela (ou seja, se uma carta)

    ⊢⌿ última linha, ou seja, para o caractere da partida, seja uma letra

   1∘⌷≠ XOR com a primeira linha, ou seja, se cada caractere Ré maiúsculo

  ()l¨⍨ Use isso para minúsculas (se 0) ou maiúsculas (se 1) cada letra de:

   ⊣⌿ a primeira linha, ou seja R


* Contagem de bytes para o Dyalog Classic usando em ⎕OPT vez de .

Adão
fonte
2

Perl 5 , 108 bytes

Código de 107 bytes + 1 para -p.

chomp(($s,$r)=<>);s|\Q$s|$&=~s!.!$_=substr$r,"@-",1;$&=~/[a-z]/i?$&eq uc$&?uc:lc:$_!egr.substr$r,"@-"+1|gie

Experimente online!

Dom Hastings
fonte
2

Retirado. A resposta de Dom supera-a de longe.

# Perl 5 , 136 + 1 (-p) = 137 bytes

$f=<>;chomp$f;@R=($r=<>)=~/./g;for$i(/\Q$f/gi){$c=$n='';$"=$R[$c++],$n.=/[A-Z]/?uc$":/[a-z]/?lc$":$"for$i=~/./g;s/\Q$i/$n.substr$r,$c/e}

Experimente online!

fez um enorme corte depois que @Dom Hastings mencionou \Q

# Perl 5 , 176 + 1 (-p) = 177 bytes

sub h($){chomp@_;pop=~s/[^a-z0-9 ]/\\$&/gir}$f=h<>;@R=($r=<>)=~/./g;for$i(/$f/gi){$c=$n='';$"=$R[$c++],$n.=/[A-Z]/?uc$":/[a-z]/?lc$":$"for$i=~/./g;$i=h$i;s/$i/$n.substr$r,$c/e}

Experimente online!

Xcali
fonte
Agora passa em todos os casos de teste;) 108: Experimente online!
Dom Hastings
Você deve publicá-lo. Ele bate o meu um pouco.
Xcali
Justo! Foi divertido fazer isso. Eu gosto do desafio!
Dom Hastings
2

PowerShell , 190 bytes

param($T,$F,$R)[regex]::Replace($T,'(?i)'+[regex]::escape($F),{param($m)-join(0..$R.Length|%{(($y=$R[$_]),("$y"."To$((('Low','Upp')[($z="$m"[$_])-cmatch($C='[A-Z]')]))er"()))[$z-match$C]})})

Experimente online!

Explicação:

[Regex]::Replace( 
    input text T,
    Find text F with case insensitive and [regex]::escape() for symbols,
    {scriptblock} for computing the replacement
)

O scriptblock de substituição faz:

$m is the matched text with case information
loop over each character in R as $y
    $z is the same index character in $m ($null if R overruns)
    $z-match'[A-Z]' checks if alphabetic, so we must to case-match
      otherwise, non-alphabetic or null, no case-match, return $y unchanged.
    if case-matching, check if z case-sensitive matches '[A-Z]' and
      use dynamic method calling from a generated string, either 
      $y."ToLower"()
      $y."ToUpper"()
      to force the match
-join the loop output into a replacement string

Casos de teste:

function f {
param($T,$F,$R)[regex]::Replace($T,'(?i)'+[regex]::escape($F),{param($m)-join(0..$R.Length|%{(($y=$R[$_]),("$y"."To$((('Low','Upp')[($z="$m"[$_])-cmatch($C='[A-Z]')]))er"()))[$z-match$C]})})
}

Import-Module Pester

$Cases = @(
    @{Text = "Text input"; Find = "text"; Replace = "test"; Result = "Test input" }
    @{Text = "tHiS Is a PiEcE oF tExT"; Find = "is"; Replace = "abcde"; Result = "tHaBcde Abcde a PiEcE oF tExT" }
    @{Text = "The birch canoe slid on the smooth planks"; Find = "o"; Replace = " OH MY "; Result = "The birch can OH MY e slid  OH MY n the sm OH MY  OH MY th planks" }
    @{Text = "The score was 10 to 5"; Find = "10"; Replace = "tEn"; Result = "The score was tEn to 5" }
    @{Text = "I wrote my code in Brain$#@!"; Find = "$#@!"; Replace = "Friend"; Result = "I wrote my code in BrainFriend" }
    @{Text = "This challenge was created by Andrew Piliser"; Find = "Andrew Piliser"; Replace = "Martin Ender"; Result = "This challenge was created by Martin Ender" }
    @{Text = "John does not know"; Find = "John Doe"; Replace = "Jane Doe" ; Result ="Jane does not know" }
    @{Text = "Glue the sheet to the dark blue background"; Find = "Glue the sheet to the dark-blue background"; Replace = "foo"; Result ="Glue the sheet to the dark blue background" }
    @{Text = "aaa" ; Find = "aa"; Replace = "b"; Result ="ba" }
    @{Text = "aaaa"; Find = "aa"; Replace = "a"; Result ="aa" }
    @{Text = "TeXT input"; Find = "text"; Replace = "test"; Result ="TeST input" }
)

Describe "Tests" {

    It "works on /<Text>/<Find>/<Replace>/ == '<Result>'" -TestCases $Cases {
        param($Text, $Find, $Replace, $Result)
        f $Text $Find $Replace | Should -BeExactly $Result
    }

}
TessellatingHeckler
fonte
1

TXR Lisp, 285 bytes

(defun f(s f r)(let*((w(copy s))(x(regex-compile ^(compound,(upcase-str f))))(m(reverse(tok-where(upcase-str s)x))))(each((n m))(set[w n]r) (for((i(from n)))((< i (min(to n)(len w))))((inc i))(cond((chr-isupper[s i])(upd[w i]chr-toupper))((chr-islower[s i])(upd[w i]chr-tolower)))))w))

Original formatado convencionalmente:

(defun f (s f r)
  (let* ((w (copy s))
         (x (regex-compile ^(compound ,(upcase-str f))))
         (m (reverse (tok-where (upcase-str s) x))))
    (each ((n m))
      (set [w n] r)
      (for ((i (from n))) ((< i (min (to n) (len w)))) ((inc i))
        (cond ((chr-isupper [s i]) (upd [w i] chr-toupper))
              ((chr-islower [s i]) (upd [w i] chr-tolower)))))
    w))
Kaz
fonte
1

JavaScript, 177 bytes

(T,F,R)=>T.replace(eval(`/${F.replace(/[-\/\\^$*+?.()|[\]{}]/g,'\\$&')}/gi`),F=>[...R].map((r,i)=>/[A-Z]/i.test(f=F[i]||'')?r[`to${f>'`'&&f<'{'?'Low':'Upp'}erCase`]():r).join``)

Menos golfe:

(T,F,R) => T.replace(
    eval(`/${F.replace(/[-\/\\^$*+?.()|[\]{}]/g,'\\$&')}/gi`),
    F=>[...R].map((r,i) =>
        /[A-Z]/i.test(f = F[i] || '')
            ? r[`to${
                f > '`' && f < '{'
                    ? 'Low'
                    : 'Upp'
                }erCase`]()
            : r
    ).join``
)

47 bytes vieram dessa função de escape do regex, pois o programa precisa manipular símbolos. :(

darrylyeo
fonte
1

Python 2 , 193 200 bytes

T,F,R=input()
w=str.lower
i=-len(T)
l=len(F)
T+=' '
while i:
 s=T[i:i+l]
 if w(s)==w(F):T=T[:i]+`[[y,[w(y),y.upper()][x<'a']][x.isalpha()]for x,y in zip(s,R)]`[2::5]+R[l:]+T[i+l:];i+=l-1
 i+=1
print T

Experimente online!

Cajado
fonte
Isso (193 bytes, do link TIO) falhará ao encontrar correspondências no final da cadeia.
tehtmi
1

Python 3 , 183 bytes

import re
j="".join
f=lambda T,F,R:j((p,j((y,(y.lower(),y.upper())[x<'a'])[x.isalpha()]for(x,y)in zip(p,R))+R[len(F):])[i%2>0]for i,p in enumerate(re.split('('+re.escape(F)+')',T,0,2)))

Experimente online!

re.split mantenha todos os elementos pares e substitua todos os elementos ímpares pela transformação correta da sequência de substituição:

>>> re.split("(is)","tHiS Is a PiEcE oF tExT",0,2) # 2=re.IGNORE_CASE
['tH', 'iS', ' ', 'Is', ' a PiEcE oF tExT']
jferard
fonte
1

C (gcc) , 210 211 207 189 bytes

Foi necessário adicionar um byte para corrigir um erro com letras maiúsculas no caso de teste "BrainFriend"

Uau, isso foi tedioso ... Agora, para jogar fora alguns bytes

char*c,*p;d,l;f(t,f,r){for(d=isalpha(*(p=f)),p=c=t;c=strcasestr(c,f);p=c+=l>0?l:0){for(l=strlen(f);p<c;)putchar(*p++);for(p=r;*p;p++,c+=l-->0)putchar(d*l<1?*p:*c&32?*p|32:*p&~32);}puts(p);}

Experimente online!

cleblanc
fonte
Provavelmente estou perdendo algo óbvio, mas por que você precisa *(p=f)quando define p=c=tlogo depois? Eu tentei com apenas *fe não funcionou, por isso não é imediatamente substituído.
Andrew Andrew
f é por befault um int por isso não podemos excluir a referência para obter um char, mas p é um char *
cleblanc
Ah, isso faz sentido. Então é uma maneira mais curta de escrever *((char*)f)? Legal!
Andrew Andrew
1

C # (compilador Mono C #) , 241 bytes

using System.Text.RegularExpressions;
class Program {
static void Main(string[] args) {
r("Text input","text","Test");
}
static void r(string v,string i,string u)
{
System.Console.WriteLine(Regex.Replace(v,i,u,RegexOptions.IgnoreCase)); 
}
}

Experimente online!

rivalC
fonte
1
Bem-vindo ao PPCG! Você pode remover um pouco de espaço em branco aqui e, na verdade, você precisa considerar as entradas como argumentos ou como entrada (é proibido codificá-las) ou pode incluir apenas a função; você não precisa mesmo a Action<string,string,string> r =parte
HyperNeutrino