La regla general para la capitalización de títulos

30

De acuerdo con este sitio, una regla general recomendada por el Manual de Estilo de la Oficina de Imprenta del Gobierno de EE. UU. Es

Ponga en mayúscula todas las palabras en títulos de publicaciones y documentos, excepto a, an, the, at, by, for, in, of, on, up, and, as, but, or, and nor.

Esto podría no ser cierto ya que no puedo encontrar una recomendación de este tipo en el Manual de estilo , pero usemos esta regla de todos modos.


El reto

Dada una cadena de entrada que consiste en palabras minúsculas delimitadas por espacios, genera la mayúscula de la cadena de acuerdo con las siguientes reglas

  • La primera y última palabra está en mayúscula.
  • Todas las demás palabras se capitalizan, excepto una , una , el , en , por , para , de , de , de , a , a , y , tal como , pero , o , y tampoco .

La cadena de entrada contendrá al menos una palabra y cada palabra contiene al menos una letra y solo caracteres de aa z.

Este es un desafío de código de golf, así que trate de usar la menor cantidad de bytes posible en el idioma que elija. Puede escribir un programa completo o una función para realizar la tarea.

Casos de prueba

"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
fuente
1
¿Deben escribirse en mayúsculas las palabras iniciales / finales incluso si están en la lista de exclusión? Sus ejemplos dicen que sí, pero la especificación solo dice palabras en mayúscula a menos que estén en la lista, y nada sobre la primera / última palabra. Tenga en cuenta que las dos posibilidades son claramente diferentes, una es un filtro simple y la segunda requiere un comportamiento especial en casos extremos (literales).
CAD97
3
@ CAD97 Las reglas para la capitalización son los dos puntos, no la Cita. Y el primer punto dice "La primera y la última palabra están en mayúscula". y el segundo dice "Todas las demás palabras están en mayúscula, excepto ...", lo que significa que la primera y la última palabra siempre están en mayúscula.
Laikoni
Me perdí eso, de alguna manera. Aún así, gracias por aclarar.
CAD97
No estoy seguro de que sea realmente necesario especificar que cada palabra contiene al menos una letra. :)
David Conrad

Respuestas:

11

Python 2, 118 bytes

Mira ma, no 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("'"),

La entrada debe estar entre comillas. La salida tiene un espacio final y no hay nueva línea final (supongo que está bien). Verifique todos los casos de prueba en Ideone .

Explicación

Tomemos la entrada a or an como nuestro ejemplo.

Usando el `x`acceso directo de Python 2 para repr, ajustamos la entrada entre comillas simples:'a or an' . Luego nos dividimos en espacios en blanco e iteramos sobre las palabras.

Dentro del bucle, tomamos el de repr nuevo . Para la primera y última palabra, esto da "'a"y "an'". Para otras palabras, da 'or'. Queremos evitar poner en mayúsculas las palabras si se ajustan al último patrón y están en la lista de palabras cortas. Por lo tanto, podemos representar la lista de palabras como la cadena "'a'an'...'up'"y saber que reprcualquier palabra corta será una subcadena.

`w` in "..."da un valor booleano, que podemos tratar como 0o 1para fines de indexación en la lista [w.title(), w]. En resumen, titulamos la palabra en mayúscula si está al principio, al final o no en la lista de palabras cortas. De lo contrario, lo dejamos solo. Afortunadamente, title()todavía funciona como se esperaba con aportes como 'a.

Finalmente, eliminamos las comillas simples de la palabra y las imprimimos con un espacio final.

DLosc
fuente
8

05AB1E , 68 61 bytes

Guardado 7 bytes gracias a Adnan

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

Pruébalo en línea!

Explicación

“a€¤€€€›€‹€‡€†€‚€‰€„€¾€ƒ€œ€³€—š¯“es una cadena de diccionario traducida 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
fuente
2
Nunca deja de sorprenderme lo que logras lograr con una cadena corta de personajes totalmente irreconocibles. Parece que funciona entonces :) +1
ElPedro
¡Bah! Estoy tan cerca y no puedo encontrar la manera de afeitarme un personaje.
mbomb007
@ mbomb007: Mejor date prisa antes de que aparezca Jelly, MATL u otro lenguaje que pueda aplicar funciones a los índices y superar esto :) Parece que también recuerdo un lenguaje con expresiones regulares comprimidas, pero no puedo recordar cómo se llamaba. Esto es lo suficientemente largo como para que también pueda ser golfable.
Emigna
1
Para 62 bytes :)
Adnan
@Adnan: Empecé así, pero solo con las palabras de 3 caracteres (que terminaron por más tiempo), pero no consideré tomar las palabras de 2 caracteres también ... en alugar de €…guardar un byte adicional también si lideraba con eso :) Gracias!
Emigna
7

GNU sed 81 74 73 Bytes

Incluye +1 para -r

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

La primera línea escribe en mayúscula la primera letra de cada palabra. El segundo cambia todas las palabras requeridas a minúsculas.

Pruébalo en línea!

Riley
fuente
6

Retina, 69 66 bytes

Escriba con mayúscula la primera letra de cada palabra, luego cambie las palabras seleccionadas a minúsculas si no son la primera o la última palabra. Hay un espacio al final de la última línea.

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

Pruébalo en línea

Esto también funciona con un .lugar en lugar del primer espacio.

Hay muchas expresiones regulares con la misma longitud, pero ya no puedo encontrar una forma de recortarlas ...

mbomb007
fuente
(Este enfoque también tiene 69 bytes en Pip, pero no puedo usar el +truco para acortarlo).
DLosc
@DLosc Gracias. No sé por qué no vi eso. Estuve cerca.
mbomb007
3

JavaScript (ES6), 141 138 135 133 bytes

Guardado 3 bytes gracias 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 prueba

Arnauld
fuente
3

Jalea , 58 bytes

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

TryItOnline! o ejecutar todas las pruebas

¿Cómo?

Una cadena comprimida con espacios que separan las palabras serían 47bytes, dividiéndolo en 1bytes de costo , por 48bytes.

Dos cadenas comprimidas no separadas de las palabras de longitud 2y 3(con una 'a' al final de una) serían 40bytes más 2para dividir cada una y 1unirlas, por 45bytes.

Un número de base 250 como se describe a continuación es 32bytes, luego 3para convertir a base 26, 3para indexar en el alfabeto en minúsculas y 3dividirlo en el carácter no utilizado 'z', para41 bytes.

Entonces, la búsqueda de las palabras para no capitalizar:
“Ð/ṃƇ¬þṄẊƙ€,⁽ṙƬ®OṪJ"ɦ3×kf3Ṙç%ġu’
se formó así:

Toma esas palabras y únelas con un separador:
s="a an the at by for in of on to up and as but or nor"

Siguiente etiqueta 'a'como 1, 'b'como 2con el 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]

Convierta esto en un 26número base (la última letra utilizada es 'y'más un dígito para el separador, el código de Python para esto es:
n=sum(v*26**i for i,v in enumerate(x[::-1]))

Convierta eso en un 250número base (usando una lista para los 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]

Busque los caracteres en esos índices en la página de códigos de jelly:

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

(nota: dado que la implementación real es biyectiva, si btuviera alguna0 dígito, primero tendría que llevarlo hacia abajo)

El 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
fuente
2

PHP, 158 bytes

10 bytes guardados 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);

Versión 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
fuente
Hacer eco en el bucle ahorra 10 bytes:foreach(...)echo" "[!$k],(condition)?$v:ucfirst($v);
Titus
2

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

Ahora puede capitalizar su calculadora. Genial para la escuela :)

Programa principal, 295 bytes

Básicamente, el truco para hacer coincidir palabras para Aque no se conviertan aes encerrar espacios, como reemplazar " A "con " a ". Esto también hace que las primeras y últimas palabras permanezcan en mayúscula, ya que no tienen espacio en ambos lados y, por lo tanto, no coincidirán con ninguna de las palabras. (Genio, ¿verdad? Y súper largo porque las letras minúsculas son de dos bytes cada una ...)

"("+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 0x81y @representa token 0x7F, obtenga más información aquí .

Timtech
fuente
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 y código de prueba:

Pruébalo aquí.

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"));
  }
}

Salida:

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
fuente
1

Groovy, 131 129

Dos bytes guardados gracias a la computación caruso

{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
fuente
Bien, estaba en 137; tú ganas. Elimínelo i->y úselo itpara guardar 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()}
Urna mágica de pulpo
1
No sé Groovy, pero ¿realmente esto capitaliza la primera y la última palabra?
Emigna
@Emigna, las letras mayúsculas finales comienzan con una de las palabras.
Urna mágica de pulpo
@Emigna no realmente, omití ese requisito (esa última palabra debe escribirse en mayúscula). Necesitaría ajustar mi respuesta.
Krzysztof Atłasik
Los dos usos de .capitalize()ocupan muchos bytes. ¿Hay alguna forma de hacer un alias .capitalize()?
Cyoce
1

C #, 305 bytes

Mucho margen de mejora aún, pero aquí tienes:

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
fuente
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)}

Perdón por todas las ediciones, esta debería ser la última.

Lee W
fuente
1

Python, 177 bytes

Entregado en formato de función para guardar bytes. Esta no es una respuesta especialmente competitiva, pero es una que no requiere repr()ni regextruco. También es agnóstico a la versión; Funciona con Python 2 o 3.

Aunque es quizás una solución muy por las reglas.

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
fuente
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]));

Una fusión de la respuesta del usuario 59178 y mbomb007 .

escribe en mayúscula la primera letra de cada palabra, luego en minúscula todas las palabras de la lista rodeadas de espacios.
Desafortunadamente, la devolución de llamada tiene que operar en el conjunto completo; Esto cuesta 29 bytes.

Tito
fuente
no funciona paraa an and as at but by for in nor of on or the to up
Jörg Hülsermann
1

Raqueta 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)]))))

Sin golf:

(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)]
         )))))

Pruebas:

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

Salida:

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

Java 7 431 317 311 bytes

Gracias a @KevinCruijssen por 114 bytes.
Gracias a @RosLup por guardar 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;}

sin golf

primera respuesta por encima 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;
    }
Nudo numérico
fuente
1
Era demasiado para resumir en un comentario, pero puedes explicarlo a esto: 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 ) Sugiero echar un vistazo a lo que cambié como consejos para la próxima vez. :) PD: He publicado una respuesta con un enfoque diferente ( 259 bytes ).
Kevin Cruijssen
1
Especialmente cosas como las c.substring(0,1).toUpperCase()+c.substring(1,c.length())+" "que hiciste dos veces deberían hacerte pensar en reutilizarlo de alguna manera. Y las inicializaciones combinadas como lo hiciste correctamente con el int, pero por alguna razón no con el String. Además, no necesita el extra booleancuando puede almacenar como int0 o 1 y luego verificarlo >0. Y trataría de evitar los corchetes y breaktodo lo posible; Por lo general, hay un truco para deshacerse de ellos, como el for(f=0;f<b.length;z=c.equals(b[f++])|z>0?1:0);que he mostrado. :)
Kevin Cruijssen
1
Hay tanto que aprender y gracias por ser siempre útil (larga vida a Nederland;)
Numberknot
1
Oh, he cometido un error de copiar y pegar. Debería ser esto 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;}y no hay problema. :) También aprendí mucho cuando era nuevo en el golf de código. Solo hago una lista con cada consejo general de codegolf que aprendo y lo veo / actualizo a veces. Pero mi código todavía es muy usado por otros.
Kevin Cruijssen
1
En la cadena b [] hay 2 'y' ¿está bien?
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])),'!',' ');

Utiliza el comportamiento ucwords()y escapa de las palabras relevantes que están rodeadas por espacios y luego elimina los caracteres de escape.

Copié el (a[snt]?|and|[fn]or|up|by|but|the|to|in|o[rnf]) de la respuesta de Jörg Hülsermann pero a medida que el enfoque es completamente diferente que lo pongo como una respuesta por separado.

editar: error notado por Titus, arreglarlo cuesta 1 byte. también: 6 bytes guardados gracias a su útil comentario sobre strtr

usuario59178
fuente
Ahorre 6 bytes con en strtrlugar de str_replace. O anteponga las palabras con <>y suelte the str_replacey use la salida HTML.
Titus
En algunos casos puede usar en preg_filterlugar de preg_replace. No lo he
probado
La expresión regular no funcionará para dos palabras de la lista en una fila; prueba nice try for a start. Reemplazar uno de los espacios con una aserción resuelve eso (+4 bytes).
Titus
Lamentablemente preg_filterfallaría en el titlecaso de prueba, sin devolver nada.
user59178
1

Puro bash - 253

(no se llaman programas externos) - necesita 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

vista normal con comentarios

#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

salida

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
fuente
1

Japt , 71 bytes

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

Pruébalo en línea!

Explicación:

£`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

Una de mis características favoritas de Japt es su compresión de cadenas, que utiliza la biblioteca shoco .

Puede comprimir una cadena envolviéndola en Oc"{string}"Oc"a an the at by for in of on to up and as but or nor"

Luego descomprimirlo con backticks o Od"{compressed string}"Od"a e by f up d ¿t n"

Oliver
fuente
La -Sbandera se agregó después de publicar este desafío, por lo que su solución actual no es competitiva. Sin embargo, creo que puede hacerlo £...+XÅ}S, lo que estaría compitiendo por el mismo conteo de bytes (¡ Pruébelo en línea! )
ETHproductions
¿Cómo se compara shoco con la compresión del diccionario de Jelly en tu opinión?
Robert Fraser
@RobertFraser En comparación con Jelly, no es muy bueno para comprimir cadenas de palabras en inglés, pero es muy bueno para comprimir cadenas de letras minúsculas arbitrarias, lo que a veces resulta útil.
ETHproductions
1

Puro 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
}

Al igual que la respuesta de jm66 tc acepta entrada estándar.

agc
fuente
0

En realidad , 79 bytes

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

Pruébalo en línea!

Explicación:

' ,ÿ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
fuente
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%

Con comentarios:

@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
fuente