A regra de ouro para a capitalização de títulos

30

De acordo com este site, uma regra geral recomendada pelo Manual de Estilo do Gabinete de Impressão do Governo dos EUA é

Coloque todas as palavras em maiúsculas em títulos de publicações e documentos, exceto a, an, the, at, by, for, in, of, on, to, up e and, as, but, or, and nor.

Isso pode não ser verdade, pois não consigo encontrar essa recomendação no Manual de estilo , mas vamos usar essa regra de qualquer maneira.


O desafio

Dada uma sequência de entrada que consiste em palavras em minúsculas delimitadas por espaços, produza a capitalização da sequência de acordo com as seguintes regras

  • A primeira e a última palavra são maiúsculas.
  • Todas as outras palavras são capitalizados, exceto um , um , o , a , por , para , em , de , em , para , se , e , como , mas , ou , e nem .

A sequência de entrada conterá pelo menos uma palavra e cada palavra conterá pelo menos uma letra e apenas caracteres de aaté z.

Este é um desafio de código de golfe, portanto, tente usar o mínimo de bytes possível no idioma de sua escolha. Você pode escrever um programa completo ou uma função para realizar a tarefa.

Casos de teste

"the rule of thumb for title capitalization" -> "The Rule of Thumb for Title Capitalization"
"programming puzzles and code golf" -> "Programming Puzzles and Code Golf"
"the many uses of the letter a" -> "The Many Uses of the Letter A"
"title" -> "Title"
"and and and" -> "And and And"
"a an and as at but by for in nor of on or the to up" -> "A an and as at but by for in nor of on or the to Up"
"on computable numbers with an application to the entscheidungsproblem" -> "On Computable Numbers With an Application to the Entscheidungsproblem"
Laikoni
fonte
1
As palavras iniciais / finais devem ser colocadas em maiúsculas, mesmo que estejam na lista de exclusão? Seus exemplos dizem que sim, mas as especificações dizem apenas letras maiúsculas, a menos que estejam na lista e nada sobre a primeira / última palavra. Observe que as duas possibilidades são distintamente diferentes, uma sendo um filtro simples e a segunda exigindo comportamento especial em casos de borda (literais).
CAD97
3
@ CAD97 As regras para a capitalização são os dois pontos principais, não a Cotação. E o primeiro ponto diz "A primeira e a última palavra são maiúsculas". e o segundo diz "Todas as outras palavras são maiúsculas, exceto ...", significando que a primeira e a última palavra são sempre maiúsculas.
Laikoni 26/10/16
Eu senti falta disso, de alguma forma. Ainda assim, obrigado por esclarecer.
CAD97
Não tenho certeza se é realmente necessário especificar que cada palavra contenha pelo menos uma letra. :)
David Conrad

Respostas:

11

Python 2, 118 bytes

Olha ma, sem regex!

for w in`input()`.split():print[w.title(),w][`w`in"'a'an'and'as'at'the'by'but'for'nor'in'of'on'or'to'up'"].strip("'"),

A entrada deve estar entre aspas. A saída tem um espaço à direita e nenhuma nova linha à direita (presumo que esteja tudo bem). Verifique todos os casos de teste no Ideone .

Explicação

Vamos tomar a entrada a or ancomo nosso exemplo.

Usando do Python 2 `x`atalho para repr, nós envolvemos a entrada entre aspas simples: 'a or an'. Em seguida, dividimos em espaço em branco e iteramos sobre as palavras.

Dentro do loop, pegamos repr novamente . Para a primeira e a última palavra, isso fornece "'a"e "an'". Por outras palavras, dá 'or'. Queremos evitar letras maiúsculas se elas se encaixam no último padrão e estão na lista de palavras curtas. Portanto, podemos representar a lista de palavras como a sequência "'a'an'...'up'"e saber que a reprpalavra curta será uma substring.

`w` in "..."fornece um valor booleano, que podemos tratar como 0ou 1para fins de indexação na lista [w.title(), w]. Em resumo, colocamos a palavra em maiúsculas e minúsculas se estiver no início, no final ou não na lista de palavras curtas. Caso contrário, deixamos em paz. Felizmente, title()ainda funciona como esperado, com entradas como 'a.

Por fim, separamos as aspas simples da palavra e a imprimimos com um espaço à direita.

DLosc
fonte
8

05AB1E , 68 61 bytes

Economizou 7 bytes graças a Adnan

™ð¡Dg<UvyN__NXQ_“a€¤€€€›€‹€‡€†€‚€‰€„€¾€ƒ€œ€³€—š¯“#™yå&&il})ðý

Experimente online!

Explicação

“a€¤€€€›€‹€‡€†€‚€‰€„€¾€ƒ€œ€³€—š¯“é uma string de dicionário traduzida como a an the at by for in of on to up and as but or nor.

™                          # title case input string
ð¡                         # split on spaces
Dg<U                       # store index of last word in X

vy                         # for each word
  N__                      # is it not first index?
     NXQ_                  # is it not last index
         “...“             # the compressed string 
              #            # split on spaces
               ™           # convert to title case
                yå         # is current word in this list?
                  &&       # and the 3 previous conditions together
                    il     # if all are true, convert to lower case
                      }    # end loop
)ðý                        # wrap stack in list and join by spaces
Emigna
fonte
2
Nunca deixa de me surpreender o que você consegue alcançar com uma pequena sequência de caracteres totalmente irreconhecíveis. Parece que funciona então :) +1
ElPedro 26/10
Bah! Estou tão perto e não consigo encontrar uma maneira de raspar um personagem.
mbomb007
@ mbomb007: É melhor se apressar antes que o Jelly, o MATL ou alguma outra linguagem que possa aplicar funções aos índices chegue e supere isso :) Parece que me lembro de uma linguagem com regex compactado também, mas não consigo lembrar como era chamada. Isso é longo o suficiente para que ainda possa ser jogado também.
Emigna
1
Para 62 bytes :)
Adnan
@Adnan: Comecei assim, mas apenas com as palavras de 3 caracteres (que terminaram mais longas), mas não considerei usar as palavras de 2 caracteres também ... em avez de €…salvar um byte adicional, bem como a liderança de com ele :) Obrigado!
Emigna
7

GNU sed 81 74 73 bytes

Inclui +1 para -r

s/\b./\u&/g
:;s/.(And?|A[st]?|The|By|But|[FN]or|In|O[fnr]|To|Up) /\L&/;t

A primeira linha coloca em maiúscula a primeira letra de cada palavra. O segundo alterna todas as palavras necessárias de volta para minúsculas.

Experimente Online!

Riley
fonte
6

Retina, 69 66 bytes

Coloque em maiúscula a primeira letra de cada palavra e altere as palavras selecionadas para minúsculas, se não forem a primeira ou a última palavra. Há um espaço no final da última linha.

T`l`L`\b.
+T`L`l` (And?|A[st]?|The|By|But|[FN]or|In|O[fnr]|To|Up) 

Experimente online

Isso também funciona com um espaço em .vez do primeiro.

Existem muitas regexes com o mesmo comprimento, mas não consigo mais encontrar uma maneira de apará-las ...

mbomb007
fonte
(Essa abordagem também é 69 bytes em Pip, mas eu não posso usar o +truque para encurtá-lo.)
DLosc
@DLosc Obrigado. Idk porque eu não vi isso. Eu estava perto
mbomb007
3

JavaScript (ES6), 141 138 135 133 bytes

Guardado 3 bytes graças a mbomb007

s=>s.replace(/(\w+)( ?)/g,(a,w,n,i)=>i&&n&&/^(a[nst]?|the|by|in|of|on|to|up|and|but|[fn]?or)$/.exec(w)?a:a[0].toUpperCase()+a.slice(1))

Casos de teste

Arnauld
fonte
3

Geléia , 58 bytes

“Ð/ṃƇ¬þṄẊƙ€,⁽ṙƬ®OṪJ"ɦ3×kf3Ṙç%ġu’b26ịØaṣ”z
e€¢¬T;2Ḷ¤
ḲŒtǦK

TryItOnline! ou execute todos os testes

Quão?

Uma string compactada com espaços que separam as palavras seria 47bytes, dividindo os custos em 1bytes, para 48bytes.

Duas seqüências de caracteres compactadas não separadas das palavras length 2e 3(com um 'a' no final de uma), respectivamente, seriam 40bytes mais 2para dividir cada uma e 1unir-se a elas, por 45bytes.

Um número de base 250, conforme descrito abaixo, é 32bytes, 3para converter na base 26, 3indexar no alfabeto em minúsculas e 3dividi-lo no caractere não utilizado 'z', em 41bytes.

Assim, a busca pelas palavras para não capitalizar:
“Ð/ṃƇ¬þṄẊƙ€,⁽ṙƬ®OṪJ"ɦ3×kf3Ṙç%ġu’
foi formada assim:

Pegue essas palavras e junte-se a elas com um separador:
s="a an the at by for in of on to up and as but or nor"

Próximo rótulo 'a'como 1, 'b'como 2no separador, como 0:

alpha = ' abcdefghijklmnopqrstuvwxyz'
x = [alpha.index(v) for v in s]
x
[1,0,1,14,0,20,8,5,0,1,20,0,2,25,0,6,15,18,0,9,14,0,15,6,0,15,14,0,20,15,0,21,16,0,1,14,4,0,1,19,0,2,21,20,0,15,18,0,14,15,18]

Converta isso em um 26número base (a última letra usada é 'y'mais um dígito para o separador, o código Python para isso é:
n=sum(v*26**i for i,v in enumerate(x[::-1]))

Converta isso em um 250número base (usando uma lista para os dígitos):

b=[]
while n:
    n,d = divmod(n,250)
    b=[d]+b
b
[16,48,220,145,8,32,202,209,162,13,45,142,244,153,9,80,207,75,35,161,52,18,108,103,52,205,24,38,237,118]

Pesquise os caracteres nesses índices na página de códigos da geléia:

codepage = '''¡¢£¤¥¦©¬®µ½¿€ÆÇÐÑ×ØŒÞßæçðıȷñ÷øœþ !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQR TUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~¶°¹²³⁴⁵⁶⁷⁸⁹⁺⁻⁼⁽⁾ƁƇƊƑƓƘⱮƝƤƬƲȤɓƈɗƒɠɦƙɱɲƥʠɼʂƭʋȥẠḄḌẸḤỊḲḶṂṆỌṚṢṬỤṾẈỴẒȦḂĊḊĖḞĠḢİĿṀṄȮṖṘṠṪẆẊẎŻạḅḍẹḥịḳḷṃṇọṛṣṭụṿẉỵẓȧḃċḋėḟġḣŀṁṅȯṗṙṡṫẇẋẏż«»‘’“”'''
r=''.join(codepage[i-1] for i in b)
r
'Ð/ṃƇ¬þṄẊƙ€,⁽ṙƬ®OṪJ"ɦ3×kf3Ṙç%ġu'

(observação: como a implementação real é bijetiva, se bhouver algum 0dígito que você precise carregar primeiro)

O resto:

ḲŒtǦK - Main link: title string
Ḳ      - split on spaces
    ¦  - apply to indexes
   Ç   -     given by calling the last link (1) as a monad (with the split title string)
 Œt    -     title case (first letter of each (only) word to upper case)
     K - join on spaces

e€¢¬T;2Ḷ¤ - Link 1, find indexes to capitalise: split title string
e€        - is an element of, for €ach
  ¢       - the result of calling the last link (2) as a nilad
   ¬      - logical not
    T     - get the truthy indexes (indexes of words that are not in the list)
     ;    - concatenate with
        ¤ - nilad followed by link(s) as a nilad
      2Ḷ  - range(2) -> [0,1]
                (we always want to capitalise the first index, 1, and the last index, 0)

“Ð/ṃƇ¬þṄẊƙ€,⁽ṙƬ®OṪJ"ɦ3×kf3Ṙç%ġu’b26ịØaṣ”z - Link 2, make the word list: no arguments
“Ð/ṃƇ¬þṄẊƙ€,⁽ṙƬ®OṪJ"ɦ3×kf3Ṙç%ġu’          - the base 250 number
                                b26       - convert to base 26
                                   ị      - index into
                                    Øa    - lowercase alphabet
                                      ṣ   - split on
                                       ”z - literal 'z' (the separator 0 indexes into `z`)
Jonathan Allan
fonte
2

PHP, 158 bytes

10 bytes salvos por @Titus

foreach($w=explode(" ",$argv[1])as$k=>$v)echo" "[!$k],$k&&$k+1<count($w)&&preg_match("#^(a[snt]?|and|[fn]or|up|by|but|the|to|in|o[rnf])$#",$v)?$v:ucfirst($v);

Versão anterior PHP, 174 Bytes

foreach($w=explode(" ",$argv[1])as$k=>$v)$k&&$k+1<count($w)&&in_array($v,[a,an,the,at,by,"for",in,of,on,to,up,"and","as",but,"or",nor])?:$w[$k]=ucfirst($v);echo join(" ",$w);
Jörg Hülsermann
fonte
O eco no loop salva 10 bytes:foreach(...)echo" "[!$k],(condition)?$v:ucfirst($v);
Titus
2

TI-Basic, 295 + 59 + 148 = 502 bytes

Agora você pode capitalizar sua calculadora. Ótimo para a escola :)

Programa principal, 295 bytes

Basicamente, o truque para combinar palavras para que tudo Anão se torne aé colocar espaços, como substituir " A "por " a ". Isso também faz automaticamente com que a primeira e a última palavras fiquem em maiúsculas, porque elas não têm espaço nos dois lados e, portanto, não correspondem a nenhuma das palavras. (Gênio, certo? E super longo, porque letras minúsculas têm dois bytes cada ...)

"("+Ans+")→Str1
"@A ~ a@An ~ an@The ~ the@At ~ at@By ~ by@For ~ for@In ~ in@Of ~ of@On ~ on@To ~ to@Up ~ up@And ~ and@As ~ as@But ~ but@Or ~ or@Nor ~ nor@→Str2
For(I,2,length(Ans
If "@"=sub(Str2,I-1,1
Then
" "+Str1+"~"+sub(Str2,I,inString(Str2,"@",I)-I)+" "
prgmQ
Ans→Str1
End
End

Subprograma ( prgmQ), 59 bytes:

Ans→Str9
inString(Ans,"~
sub(Str9,Ans,length(Str9)-Ans+1→Str8
Str9
prgmR
Repeat Str9=Ans+Str8
Ans+Str8→Str9
prgmR
End

Subprograma ( prgmR), 148 bytes:

Ans→Str0
inString(Ans,"~→Z
inString(Str0,"~",Ans+1→Y
inString(sub(Str0,1,Z-1),sub(Str0,Z+1,Ans-Z-1→X
sub(Str0,1,-1+inString(Str0,"~
If X
sub(Str0,1,X-1)+sub(Str0,Y+1,length(Str0)-Y)+sub(Str0,X+length(sub(Str0,Z+1,Y-Z-1)),Z-X-length(sub(Str0,Z+1,Y-Z-1

PS ~representa token 0x81e @representa token 0x7F, saiba mais aqui .

Timtech
fonte
2

Java 7, 271 259 258 bytes

String c(String x){String a[]=x.split(" "),s=" ",r=w(a[0])+s;for(int i=0,l=a.length-1;i<l;r+=(!s.matches("^(a[nst]?|the|by|in|of|on|to|up|and|but|[fn]?or)$")|i==l?w(s):s)+" ")s=a[++i];return r;}String w(String w){return(char)(w.charAt(0)-32)+w.substring(1);}

Ungolfed & código de teste:

Experimente aqui.

class M{
  static String c(String x){
    String a[] = x.split(" "),
           s = " ",
           r = w(a[0]) + s;
    for(int i = 0, l = a.length-1; i < l; r += (!s.matches("^(a[nst]?|the|by|in|of|on|to|up|and|but|[fn]?or)$") | i == l
                                                 ? w(s)
                                                 : s)   + " "){
      s = a[++i];
    }
    return r;
  }

  static String w(String w) {
    return (char)(w.charAt(0) - 32) + w.substring(1);
  }

  public static void main(String[] a){
    System.out.println(c("the rule of thumb for title capitalization"));
    System.out.println(c("programming puzzles and code golf"));
    System.out.println(c("the many uses of the letter a"));
    System.out.println(c("title"));
    System.out.println(c("and and and"));
    System.out.println(c("a an and as at but by for in nor of on or the to up"));
    System.out.println(c("on computable numbers with an application to the entscheidungsproblem"));
  }
}

Saída:

The Rule of Thumb for Title Capitalization 
Programming Puzzles and Code Golf 
The Many Uses of the Letter A 
Title 
And and And 
A an and as at but by for in nor of on or the to Up 
On Computable Numbers With an Application to the Entscheidungsproblem 
Kevin Cruijssen
fonte
1

Groovy, 131 129

Dois bytes economizados graças à carusocomputação

{it.split()*.with{a->a in "a an the at by for in of on to up and as but or nor".split()?a:a.capitalize()}.join(" ").capitalize()}
Krzysztof Atłasik
fonte
Bom, eu tinha 137 anos; você ganha. Remova i->e use itpara salvar 2 bytes. {it.split()*.with{a->a in "a an the at by for in of on to up and as but or nor".split()?a:a.capitalize()}.join(" ").capitalize()}
Magic Octopus Urn
1
Não conheço Groovy, mas isso realmente capitaliza a primeira e a última palavra?
Emigna
@Emigna, as letras maiúsculas finais começam com uma das palavras.
Magic Octopus Urn
@ Emigna não é verdade, eu perdi esse requisito (essa última palavra precisa ser maiúscula). Eu precisaria ajustar minha resposta.
Krzysztof Atłasik 26/10
Os dois usos de .capitalize()ocupam muitos bytes. Existe uma maneira curta de criar um alias para .capitalize()?
Cyoce 2/11/16
1

C #, 305 bytes

Ainda há muito a melhorar, mas aqui está:

s=>{;var b=s.Split(' ');b[0]=((char)(b[0][0]-32))+b[0].Substring(1);int i=0,n=b.Length;for(;++i<n;)if(!"a,an,the,at,by,for,in,of,on,to,up,and,as,but,or,nor".Split(',').Contains(b[i]))b[i]=((char)(b[i][0]-32))+b[i].Substring(1);b[n-1]=((char)(b[n-1][0]-32))+b[n-1].Substring(1);return string.Join(" ",b);};
TheLethalCoder
fonte
1

Ruby, 123 117 111 102 bytes

->s{s.gsub(/ .|^./,&:upcase).gsub(/ (A[nts]?|The|By|In|To|Up|And|But|[NF]or|O[rnf])(?= )/,&:downcase)}

Desculpe por todas as edições - essa deve ser a última.

Lee W
fonte
1

Python, 177 bytes

Entregue em formato de função para fins de economia de bytes. Esta não é uma resposta especialmente competitiva, mas é uma resposta que não exige repr()nem regextrapaça. Também é independente de versão; funciona com Python 2 ou 3.

Embora seja talvez uma solução muito rígida.

def t(s):
 w="a an the the at by for in of on to up and as but or nor".split()
 l=[(s.title(),s)[s in w]for s in s.split()]
 for x in(0,-1):l[x]=l[x].title()
 return' '.join(l)
James Murphy
fonte
1

PHP, 109 142 bytes

<?=preg_replace_callback("# (A[snt]?|And|[FN]or|Up|By|But|The|To|In|O[rnf])(?= )#",function($m){return strtolower($m[0]);},ucwords($argv[1]));

Uma fusão das respostas de user59178 e mbomb007 .

em maiúsculas a primeira letra de cada palavra e, em minúsculas, todas as palavras da lista, cercadas por espaços.
Infelizmente, o retorno de chamada precisa operar no conjunto completo; isso custa 29 bytes.

Titus
fonte
isso não funcionaa an and as at but by for in nor of on or the to up
Jörg Hülsermann 28/10
1

Raquete 353 bytes

(define(cap i)(set! i(string-append i))(define c(string-ref i 0))(string-set! i 0(if(char-upper-case? c)c(integer->char(-(char->integer c)32))))i)
(let*((ex(list"a""an""the""at""by""for""in""of""on""to""up""and""as""but""or""and""nor"))(sl(string-split s)))
(string-join(for/list((i sl)(n(in-naturals)))(cond[(= n 0)(cap i)][(member i ex)i][(cap i)]))))

Ungolfed:

(define (f s)

  (define (cap i)                 ; sub-fn to capitalize first letter of a word
    (set! i (string-append i))
    (define c (string-ref i 0))
    (string-set! i 0
                 (if (char-upper-case? c)
                     c
                     (integer->char (-(char->integer c)32))))
    i)

  (let* ((ex (list "a""an""the""at""by""for""in""of""on""to""up""and""as""but""or""and""nor"))
         (sl (string-split s)))
    (string-join
     (for/list
         ((i sl)
          (n (in-naturals)))
       (cond
         [(= n 0) (cap i)]
         [(member i ex) i]
         [(cap i)]
         )))))

Teste:

(f "the rule of thumb for title capitalization")

Saída:

"The Rule of Thumb for Title Capitalization"
rnso
fonte
1

Java 7, 431 317 311 bytes

Obrigado a @KevinCruijssen por 114 bytes.
Obrigado a @RosLup por salvar 6 bytes.

String c(String s){String v="",x,l[]=s.split(" "),b[]={"a","an","the","at","but,"by","for","in","of","on","to","‌​up","as","or","and","nor"};int i=0,f=0,z=0;for(String c:l){for(f=0;f<b.length;z=c.equals(b[f++])|z>0?1:0);x=(char)(c.charAt(0)-32)+c.substring(1);v+=(z>0?i<1|i>l.length-2?x:c:x)+" ";i++;}return v;}

destroçado

primeira resposta acima de 250 bytes

 static String c(String s) {
      String v = "", x, l[] = s.split(" "),
b[]={"a","an","the","at","by","for","in","of","on","to",
                                         "‌​up","and","as","or","nor","but"};
    int i , f , z = i = f = 0;
    for (String c : l) {

   for (f = 0; f < b.length; z = c.equals( b[f++] ) | z > 0 ? 1 : 0);
        x = (char)(c.charAt(0) - 32) + c.substring(1);

        v += (z > 0 ? i < 1 | i > l.length - 2 ? x : c : x) + " ";
        i++;
   }
    return v;
    }
Numberknot
fonte
1
Foi demais para resumir em um comentário, mas você pode fazer o seguinte: String f(String s){String v="",x,l[]=s.split(" "),b[]={"a","an","the","at","by","for","in","of","on","to","up","and","as","but","or","and","nor"};int i=0,f=0,z=0;for(String c:l){for(f=0;f<b.length;z=c.equals(b[f++])|z>0?1:0);x=(char)(c.charAt(0)-32)+c.substring(1);v+=z>0?i<1|i++==l.length-1?x:c:x)+" ";}return v;}( 314 bytes ) Sugiro dar uma olhada no que mudei como dicas para a próxima vez. :) PS: Publiquei uma resposta com uma abordagem diferente ( 259 bytes ).
Kevin Cruijssen 27/10
1
Especialmente coisas c.substring(0,1).toUpperCase()+c.substring(1,c.length())+" "que você fez duas vezes devem fazer você pensar em reutilizá-lo de alguma forma. E inicializações combinadas como você fez corretamente com o int, mas por algum motivo não com o String. Além disso, não há necessidade de extra booleanquando você pode armazenar como int0 ou 1 e depois verificá-lo >0. E tentaria evitar colchetes e breako máximo possível; geralmente há um truque para se livrar deles, como o for(f=0;f<b.length;z=c.equals(b[f++])|z>0?1:0);que eu mostrei. :)
Kevin Cruijssen 27/10
1
Tanta coisa para aprender e obrigado por ser útil sempre (viva Nederland;) #
Numberknot 27/10/16
1
Ah, eu cometi um erro de copiar e colar .. Deve ser isso String c(String s){String v="",x,l[]=s.split(" "),b[]={"a","an","the","at","by","for","in","of","on","to","up","and","as","but","or","and","nor"};int i=0,f=0,z=0;for(String c:l){for(f=0;f<b.length;z=c.equals(b[f++])|z>0?1:0);x=(char)(c.charAt(0)-32)+c.substring(1);v+=(z>0?i<1|i++>l.length-2?x:c:x)+" ";}return v;}E não há problema. :) Também aprendi muito quando era novo no golfe de código. Eu apenas faço uma lista com todas as dicas gerais de codegolf que eu aprendo e às vezes olho / atualizo. Mas meu código ainda é muito jogado por outros.
Kevin Cruijssen 27/10
1
Na string b [] existem 2 'e' está tudo bem?
RosLuP
1

PHP, 117 118 112 bytes

<?=strtr(ucwords(preg_replace("# (?=(a[snt]?|and|[fn]or|up|by|but|the|to|in|o[rnf]) )#","!",$argv[1])),'!',' ');

Usa o comportamento ucwords()e escapa às palavras relevantes que são cercadas por espaços e exclui os caracteres de escape.

Copiei a (a[snt]?|and|[fn]or|up|by|but|the|to|in|o[rnf])resposta de Jörg Hülsermann, mas como a abordagem é completamente diferente, estou postando como uma resposta separada.

edit: bug percebido por Titus, corrigindo o custo de 1 byte. também: 6 bytes salvos graças ao seu comentário útil sobre strtr

user59178
fonte
Salve 6 bytes com em strtrvez de str_replace. Ou acrescente as palavras com <>e solte the str_replacee use a saída HTML.
Titus
Em alguns casos, você pode usar em preg_filtervez de preg_replace. Eu não experimentá-lo com a sua solução
Jörg Hülsermann
A regex não funcionará para duas palavras da lista em uma linha; teste nice try for a start. Substituir um dos espaços por uma asserção resolve isso (+4 bytes).
Titus
Infelizmente preg_filter, falharia no titlecaso de teste, não retornando nada.
User59178
1

Pure bash - 253

(nenhum programa externo chamado) - precisa do bash v4

declare -A b;for x in A An The At By For In Of On To Up And As But Or Nor;do b[$x]=1;done
while read -a w;do
n=${#w[@]};o[0]=${w[0]^}
for((i=1;i<n-1;i++)){
g=${w[$i]^};((${b[$g]}))&&o+=(${g,,})||o+=($g);}
((n>1))&&o[$n]=${w[-1]^}
echo ${o[@]};o=()
done

visão normal com comentários

#create the "blacklist"
declare -A b
for w in A An The At By For In Of On To Up And As But Or Nor
do
    b[$x]=1
done

# logic:
# read each line (split by words) into array
# and each word is assigned capitalized to the new output array
# but the blacklisted ones

#read each line to array w (split on spaces)
while read -a w
do
    n=${#w[@]}         # get the number of words
    o[0]=${w[0]^}          # copy the capitalized word1
    for((i=1 ; i<n-1 ; i++)) { # loop over 2 up to last -1 words

        g=${w[$i]^}    # for the given word
        # check if it is in the blacklisted ones
        # if yes - convert to lowercase, if not leave as it is
        # and append to the output array
        (( ${b[$g]} )) && o+=(${g,,}) || o+=($g)
    }
    # capitalize the last word if here is more words
    (( n>1 )) && o[$n]=${w[-1]^}
    # make a line from the words
    echo ${o[@]}
    o=() #cleanup
done

saída

Title
And and And
The Rule of Thumb for Title Capitalization
Programming Puzzles and Code Golf
The Many Uses of the Letter A
A an and as at but by for in nor of on or the to Up
On Computable Numbers With an Application to the Entscheidungsproblem
jm666
fonte
1

Japonês , 71 bytes

£`a  e  by f     up d  ¿t  n`¸aX >0©Y¦0©YĦZl ?X:Xg u +XÅ}S

Experimente online!

Explicação:

£`a  e  by f     up d  ¿t  n`¸aX >0©Y¦0©YĦZl ?X:Xg u +XÅ}S
£`...`qS aX >0&&Y!=0&&Y!=UqS l -1?X:Xg u +Xs1}S

£                                            }S   // Split at spaces and map each item X by this function:
 `...`                                            //  Backticks are used to decompress strings
      qS                                          //  Split the decompressed string at spaces.
         aX >J                                    //  If this contains X
              &&Y!=0                              //  and the index is non-zero (it's not the first word)
                    &&Y!=UqS l -1                 //  and the index is not the length of the input -1 (it's not the last word),
                                 ?X               //  return X.
                                   :Xg u +Xs1     //  Else, return X capitalized. (Literally X[0].toUpperCase() + X.slice(1))
                                             }S   // Rejoin with spaces

Um dos meus recursos favoritos do Japt é a compactação de strings, que usa a biblioteca shoco .

Você pode compactar uma string envolvendo-a em Oc"{string}"Oc"a an the at by for in of on to up and as but or nor"

Em seguida, descompacte-o com backticks ou Od"{compressed string}"Od"a e by f up d ¿t n"

Oliver
fonte
A -Ssinalização foi adicionada após o lançamento deste desafio, portanto sua solução atual não é concorrente. No entanto, eu acho que você pode fazer £...+XÅ}S, que estaria competindo para o mesmo byte-count ( Experimente online! )
ETHproductions
Como o shoco se compara à compressão do dicionário Jelly na sua opinião?
Robert Fraser
@RobertFraser Comparado ao Jelly, não é muito bom em comprimir seqüências de palavras em inglês, mas é muito bom em comprimir seqüências de letras minúsculas arbitrárias, o que às vezes é útil.
ETHproductions
1

Pure bash - 205 192 181 bytes

tc(){
while read -a x
do x=(${x[@]^})
for ((i=1;i<${#x[@]}-1;i++))
do
case "${x[i]}" in
A|A[nts]|The|By|[FN]or|In|O[fnr]|To|Up|And|But)x[i]=${x[i],};;
esac
done
echo ${x[@]}
done
}

Como a resposta do jm66, tc aceita entrada padrão.

agc
fonte
0

Na verdade , 79 bytes

' ,ÿsd@p@`;0"A0An0The0At0By0For0In0Of0On0To0Up0And0As0But0Or0Nor"síu'ù*ƒ`Moq' j

Experimente online!

Explicação:

' ,ÿsd@p@`;0"longstring"síu'ù*ƒ`Moq' j
' ,ÿs                                   title case input, split on spaces
     d@p@                               pop first and last words to stack
         `;0"longstring"síu'ù*ƒ`M       for every word except the first and last:
          ;0"longstring"s                 duplicate word, split the long string on 0s
                         íu               1-based index of word in list (0 if not found)
                           'ù*            "ù"*(index)
                              ƒ           execute the resulting string as a function (lowercases word if it's in the list)
                                 oq' j  put the first and last word back in the list, join with spaces
Mego
fonte
0

Lote, 323 bytes

@echo off
set s=
for %%w in (@%*@)do call:w %%w
echo%s%
exit/b
:w
for %%s in (a an the at by for in of on to up and as but or nor)do if %%s==%1 set s=%s% %1&exit/b
set w=%1
set w=%w:@=%
set f=%w:~0,1%
for %%c in (A B C D E F G H I J K L M N O P Q R S T U V W X Y Z)do call set f=%%f:%%c=%%c%%
set s=%s% %f%%w:~1%

Com comentários:

@echo off
rem Start with an empty output string
set s=
rem Wrap the parameters in @ signs to identify the first and last words 
for %%w in (@%*@) do call :w %%w
rem Ignore the leading space when printing the result
echo%s%
exit/b
:w
rem Check whether this is a word that we don't change
for %%s in (a an the at by for in of on to up and as but or nor) do if %%s==%1 set s=%s% %1&exit/b
set w=%1
rem Delete any @ signs from the first and last words
set w=%w:@=%
rem Get the first character
set f=%w:~0,1%
rem Case insensitively replace each upper case letter with itself
for %%c in (A B C D E F G H I J K L M N O P Q R S T U V W X Y Z) do call set f=%%f:%%c=%%c%%
rem Concatenate with the rest of the word
set s=%s% %f%%w:~1%
Neil
fonte