|
|||
Fixnum. Los enteros fuera de este rango son
almacenados en objetos de la clase Bignum (actualmente implementados como
como un conjunto de longitud variable de pequeños enteros). Este proceso es transparente,
y Ruby gestiona automáticamente la conversión en un sentido y otro.
num = 8 7.times do print num.type, " ", num, "\n" num *= num end |
Fixnum 8 Fixnum 64 Fixnum 4096 Fixnum 16777216 Bignum 281474976710656 Bignum 79228162514264337593543950336 Bignum 6277101735386680763835789423207666416102355444464034512896 |
0 para octal, 0x para hexadecimal, o
0b para binario), seguido por una cadena de dígitos en la
base apropiada. Los caracteres de subrayado son ignorados en la cadena de dígitos.
123456 # Fixnum 123_456 # Fixnum (underscore ignored) -543 # Negative Fixnum 123_456_789_123_345_789 # Bignum 0xaabb # Hexadecimal 0377 # Octal -0b101_010 # Binary (negated) |
value & 0x9f''. La meta versión de un valor es
``value | 0x80''. Finalmente, la secuencia ?\C-? genera un borrado ASCII, 0177.
?a # character code ?\n # code for a newline (0x0a) ?\C-a # control a = ?A & 0x9f = 0x01 ?\M-a # meta sets bit 7 ?\M-\C-a # meta and control a ?\C-? # delete character |
Float, correspondiendo a tipo de datos double
correspondiente a la arquitectura nativa. Debes continuar el punto decimal con un dígito, ya que 1.e3
intentan invocar el método e3 en la clase Fixnum.
Todos los números son objetos, y responden a una variedad de mensajes (listados de manera
completa en las páginas 290, 313, 315, 323 y 349). Así que, al reves que C++, puedes encontrar
el valor absoluto de un número escribiendo aNumber.abs, no
abs(aNumber).
Los enteros también soportan varios interadores útiles. Hemos visto ya uno ---7.times
en el ejemplo de código de la página 47.
Otros incluyen por ejemplo upto y downto, para iterar arriba
y abajo entre dos enteros, y step que se parece más al tradicional bucle for.
3.times { print "X " }
1.upto(5) { |i| print i, " " }
99.downto(95) { |i| print i, " " }
50.step(80, 5) { |i| print i, " " }
|
X X X 1 2 3 4 5 99 98 97 96 95 50 55 60 65 70 75 80 |
DATA.each do |line| vals = line.split # split line, storing tokens in val print vals[0] + vals[1], " " end |
3 4 5 6 7 8 |
String#to_i
para convertir
la cadena en un entero.
DATA.each do |line| vals = line.split print vals[0].to_i + vals[1].to_i, " " end |
7 11 15 |
String.
Las cadenas son frecuentemente creadas utilizando literales de cadena
---secuencias de caracteres entre delimitadores. Debido a
que los datos en binario son dificiles de representar dentro
del código fuente del programa, puedes utilizar varias secuencias
de escape en un literal de cadena. Cada uno es reemplazado con el
valor binario correspondiente cuando el programa es compilado.
El tipo de delimitador de cadena determina el grado de sustitución
realizado. Con comillas simples, dos barras inversas son reemplazadas
con una única barra invertida, y una barra invertida seguida por una comilla
simple se convierte en una comilla simple.
'escape using "\\"'
|
» |
escape using "\"
|
'That\'s right'
|
» |
That's right
|
#{ expr }.
Si las expresión es una variable global, una variable de clase o una variable de
instancia, puedes omitir las llaves.
"Seconds/day: #{24*60*60}"
|
» |
Seconds/day: 86400
|
"#{'Ho! '*3}Merry Christmas"
|
» |
Ho! Ho! Ho! Merry Christmas
|
"This is line #$."
|
» |
This is line 3
|
%q, %Q, and ``here documents.''
%q and %Q start delimited single- and double-quoted
strings.
%q/general single-quoted string/
|
» |
general single-quoted string
|
%Q!general double-quoted string!
|
» |
general double-quoted string
|
%Q{Seconds/day: #{24*60*60}}
|
» |
Seconds/day: 86400
|
aString = <<END_OF_STRING The body of the string is the input lines up to one ending with the same text that followed the '<<' END_OF_STRING |
<<.
Normalmente, este terminador debe comenzar en la primera columna. Sin embargo,
si pones un signos menos despues de los caracteres <<, entonces puedes
identar el terminador.
print <<-STRING1, <<-STRING2 Concat STRING1 enate STRING2 |
Concat enate |
String es probablemente la clase incluida en ruby más extensa, con
más de 75 métodos estandar. No los veremos todos aquí; la referencia de la
libreria tiene la lista completa. En cambio, veremos algunos
de los más comunes que nos facilitaran la programación del día a día.
Volvamos a nuestra jukebox. Aunque está diseñada para conectarse a Internet,
también almacena copias de algunas canciones populares en un disco duro
local. De este modo, aunque una ardilla mordisquee nuestra conexión,
todavía podremos entretener a los clientes.
Por razones historicas (¿existe alguna de otro tipo?), la lista de
canciones está almacenada en filas en un fichero de texto plano. Cada
fila almacena el nombre del fichero que contiene la canción, la duración,
el artista y el título, todos en campos separados por barras verticales.
Un fichero típico podría comenzar:
/jazz/j00132.mp3 | 3:45 | Fats Waller | Ain't Misbehavin' /jazz/j00319.mp3 | 2:58 | Louis Armstrong | Wonderful World /bgrass/bg0732.mp3| 4:09 | Strength in Numbers | Texas Red : : : : |
String para extraer y limpiar los
campos antes de crear objetos Song basados en ellos.
Al menos, necesitaremos:
String#split
hará el trabajo amablemente. En
este caso, pasaremos a split una expresión regular,
/\s*\|\s*/, la cual divide la línea en trozos donde split encuentre una
barra vertical, opcionalmente rodeada por espacios. Y, como la línea del fichero tiene un caracter de nueva línea,
utilizaremos
String#chomp
para quitarselo antes
de aplicar split.
songs = SongList.new songFile.each do |line| file, length, name, title = line.chomp.split(/\s*\|\s*/) songs.append Song.new(title, name, length) end puts songs[1] |
Song: Wonderful World--Louis Armstrong (2:58) |
String#squeeze
,
el cual recurta los caracteres repetidos. Utilizaremos el formato squeeze! de este método para
alterar el valor de la cadena.
songs = SongList.new
songFile.each do |line|
file, length, name, title = line.chomp.split(/\s*\|\s*/)
name.squeeze!(" ")
songs.append Song.new(title, name, length)
end
puts songs[1]
|
Song: Wonderful World--Louis Armstrong (2:58) |
split de nuevo, esta vez dividiendo el campo tiempo alrededor
del símbolo de dos puntos.
mins, secs = length.split(/:/) |
String#scan
es similar
a split en el sentido de que rompe una cadena en varios trozos basandose en un patrón. Sin embargo, al contrario
que con split, con scan tu especificas el patron que
quieres que cumplan los trozos. En este caso, nosotros queremos que coincidan uno o más
dígitos para ambos componentes: minutos y segundos. El patrón para uno o más dígitos es: /\d+/.
songs = SongList.new
songFile.each do |line|
file, length, name, title = line.chomp.split(/\s*\|\s*/)
name.squeeze!(" ")
mins, secs = length.scan(/\d+/)
songs.append Song.new(title, name, mins.to_i*60+secs.to_i)
end
puts songs[1]
|
Song: Wonderful World--Louis Armstrong (178) |
String.
class WordIndex def initialize @index = Hash.new(nil) end def index(anObject, *phrases) phrases.each do |aPhrase| aPhrase.scan /\w[-\w']+/ do |aWord| # extract each word aWord.downcase! @index[aWord] = [] if @index[aWord].nil? @index[aWord].push(anObject) end end end def lookup(aWord) @index[aWord.downcase] end end |
String#scan
extrae los elementos de una cadena que
coincidan con una expresión regular. En este caso, el patrón ``\w[-\w']+'' coincide con cualquier caracter que
puede aparecer en una palabra, seguido por una o más de las cosas especificadas en los corchetes (un guión, otro caracter de palabra,
o una comilla simple). Hablaremos más sobre expresiones regulares, comenzando en la página 56.
Para hacer nuestras búsquedas insensibles a las mayúsculas, convertimos ambos, las palabras
que extraemos y las palabras que utilizamos como clave durante la búsqueda. Atención al símbolo de
exclamación al final del primer metodo downcase!. Como con el método squeeze! que hemos
utilizado previamente, esta es una indicación de que el método modificará al receptor, en este
caso conviertiendo una cadena a minúsculas..[Hay un pequeño error en este
ejemplo de código: la canción ``Gone, Gone, Gone'' podría ser
indexada tres veces. ¿Puedes descubrir alguna solución?]
Extenderemos nuestra clase SongList para indexar canciones tal como hemos añadido,
y añadir un método para buscar una canción dando una palabra.
class SongList def initialize @songs = Array.new @index = WordIndex.new end def append(aSong) @songs.push(aSong) @index.index(aSong, aSong.name, aSong.artist) self end def lookup(aWord) @index.lookup(aWord) end end |
songs = SongList.new
songFile.each do |line|
file, length, name, title = line.chomp.split(/\s*\|\s*/)
name.squeeze!(" ")
mins, secs = length.scan(/\d+/)
songs.append Song.new(title, name, mins.to_i*60+secs.to_i)
end
puts songs.lookup("Fats")
puts songs.lookup("ain't")
puts songs.lookup("RED")
puts songs.lookup("WoRlD")
|
Song: Ain't Misbehavin'--Fats Waller (225) Song: Ain't Misbehavin'--Fats Waller (225) Song: Texas Red--Strength in Numbers (249) Song: Wonderful World--Louis Armstrong (178) |
String. En cambio, vamos a continuar estudiando un tipo de datos
simple: rangos.
1..10 'a'..'z' 0...anArray.length |
Range contiendo referencias a dos objetos de la claseFixnum.
Si lo necesitas, puedes convertir un rango a una lista utlizando el método to_a.
(1..10).to_a
|
» |
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
('bar'..'bat').to_a
|
» |
["bar", "bas", "bat"]
|
digits = 0..9
|
||
digits.include?(5)
|
» |
true
|
digits.min
|
» |
0
|
digits.max
|
» |
9
|
digits.reject {|i| i < 5 }
|
» |
[5, 6, 7, 8, 9]
|
digits.each do |digit|
|
||
dial(digit)
|
||
end
|
||
succ retornando el siguiente objeto en la secuencia
y el objeto debe ser comparable utilizando el operador general de comparación <=>.
El operador <=> compara dos valores, devolviendo -1, 0 o +1 dependiendo
de si el primero es menor, igual o mayor que el segundo.
Aquí tenemos una clase simple que representa filas de signos ``#''.
Nosotros podríamos utilizarlo para comprobar el control de volumen de la
jukebox en modo texto.
class VU include Comparable attr :volume def initialize(volume) # 0..9 @volume = volume end def inspect '#' * @volume end # Support for ranges def <=>(other) self.volume <=> other.volume end def succ raise(IndexError, "Volume too big") if @volume >= 9 VU.new(@volume.succ) end end |
VU.
medium = VU.new(4)..VU.new(7)
|
||
medium.to_a
|
» |
[####, #####, ######, #######]
|
medium.include?(VU.new(3))
|
» |
false
|
while gets print if /start/../end/ end |
===, el operador case equality.
(1..10) === 5
|
» |
true
|
(1..10) === 15
|
» |
false
|
(1..10) === 3.14159
|
» |
true
|
('a'..'j') === 'c'
|
» |
true
|
('a'..'j') === 'z'
|
» |
false
|
line.split(/\s*\|\s*/) buscaba coincidencias con una
barra vertical rodeada por espacios en blanco opcionales. Vamos a explorar las expresiones regulares en
más detalle para ver por qué esta afirmación es cierta.
Las expresiones regulares son utilizadas para buscar coincidencias de patrones con
cadenas. Ruby proporciona soporte incorporado que hace la coincidencia de patrones
y la sustitución cómoda y concisa. In esta sección trabajaremos sobre las
carácterísticas fundamentales de las expresiones regulares. Existen algunos
detalles que no cubriremos: hay que echar un vistazo a la página 205 para más
información.
Las expresiones regulares son objetos del tipo Regexp. Puden ser creadas
llamando al constructor de forma explicita o utilizan el formato literal /pattern/ y %r\pattern\.
a = Regexp.new('^\s*[a-z]')
|
» |
/^\s*[a-z]/
|
b = /^\s*[a-z]/
|
» |
/^\s*[a-z]/
|
c = %r{^\s*[a-z]}
|
» |
/^\s*[a-z]/
|
Regexp#match(aString) o el operador de coincidencia =~
(coincidencia positiva) and !~
(coincidencia negativa). Los operadores de coincidencia están definidos para ambos, los objetos String y Regexp.
Si ambos operandos del operador de coincidencia son Strings, el de la derecha será convertido en una
expresión regular.
a = "Fats Waller"
|
||
a =~ /a/
|
» |
1
|
a =~ /z/
|
» |
nil
|
a =~ "ll"
|
» |
7
|
$& recibe la parte d e la cadena que coincidió con
el patrón, $` recibe la parte de la cadena que precede a la coincidencia, y $' recibe la cadena detrás de la
coincidencia. Podemos utilizar esto para escribir un método, showRE, el cual ilustra
donde un patrón particular coincide.
def showRE(a,re)
|
||
if a =~ re
|
||
"#{$`}<<#{$&}>>#{$'}"
|
||
else
|
||
"no match"
|
||
end
|
||
end
|
||
|
||
showRE('very interesting', /t/)
|
» |
very in<<t>>eresting
|
showRE('Fats Waller', /ll/)
|
» |
Fats Wa<<ll>>er
|
$~ y
$1 hasta $9.
La variable $~ es un objetode la clase MatchData
(descrito al comienzo de la página 336) que almacena todo lo que deberías saber sobre
la coincidencia. Hablaremos osbre eso más tarde. Y para la gente que se acobarda
cuando ven esos nombres de variable que suenan a Perl, estad atentos. Hay buenas
noticas al final de capítulo.
showRE('kangaroo', /angar/)
|
» |
k<<angar>>oo
|
showRE('!@%&-_=+', /%&/)
|
» |
!@<<%&>>-_=+
|
/\s*\|\s*/. El \| significa
``coincidir con una barra vertical.'' Sin la barra invertida, el ``|'' podría significarw alternacia (la cual describiremos más tarde).
showRE('yes | no', /\|/)
|
» |
yes <<|>> no
|
showRE('yes (no)', /\(no\)/)
|
» |
yes <<(no)>>
|
showRE('are you sure?', /e\?/)
|
» |
are you sur<<e?>>
|
#{...}, una expresión de sustitución.
/iss/ contra la cadena
``Mississippi,'' y encontrarás la subcadena ``iss'' comenzando en la posición uno.
¿Pero qué sucede si quieres forzar un patrón para ser comparado al comienzo o al final
de la cadena?
Los patrones ^
y $ casan con el principio y el fin de la linea, respectivamente.
Son utilizados frecuentemente para amarrar un patrón: por ejemplo, /^option/
concuerda con la palabra ``option'' sólo si aparece al comienzo de la línea.
La secuencia \A encaja con el final de la cadena. (Realmente, \Z encaja con el final de una cadena
a no ser que la cadena termine con un ``\n'', en cuyo caso coincide justo antes de ``\n''.)
showRE("this is\nthe time", /^the/)
|
» |
this is\n<<the>> time
|
showRE("this is\nthe time", /is$/)
|
» |
this <<is>>\nthe time
|
showRE("this is\nthe time", /\Athis/)
|
» |
<<this>> is\nthe time
|
showRE("this is\nthe time", /\Athe/)
|
» |
no match
|
\b and \B match word boundaries
and nonword boundaries, respectively. Word characters are letters,
numbers, and underscore.
showRE("this is\nthe time", /\bis/)
|
» |
this <<is>>\nthe time
|
showRE("this is\nthe time", /\Bis/)
|
» |
th<<is>> is\nthe time
|
[
characters
] encaja con cualquier caracter entre los corchetes.
[aeiou] encajará con cualquier vocal, [,.:;!?] encaja con signos de puntuación
y así podríamos continuar. El significado de la expresión regular especial caracteres---.|()[{+^$*?---es repelida dentro
de los corchetes. Sin embargo, la sustitución normal de cadena continúa ocurriendo, así que (por ejemplo) \b representa un caracter
de retroceso y \n una nueva línea (ver tabla 18.2 en page 203). Adicionalmente,
puedes utilizar las abreviaturas mostradas en la tabla 5.1 de la página 59, así que (por ejemplo) \s encaja con cualquier caracter de
espacio en blanco, no sólo un espacio literal.
showRE('It costs $12.', /[aeiou]/)
|
» |
It c<<o>>sts $12.
|
showRE('It costs $12.', /[\s]/)
|
» |
It<< >>costs $12.
|
] y - dentro
de una clase caracter, deben aparecer al comienzo.
a = 'Gamma [Design Patterns-page 123]'
|
||
showRE(a, /[]]/)
|
» |
Gamma [Design Patterns-page 123<<]>>
|
showRE(a, /[B-F]/)
|
» |
Gamma [<<D>>esign Patterns-page 123]
|
showRE(a, /[-]/)
|
» |
Gamma [Design Patterns<<->>page 123]
|
showRE(a, /[0-9]/)
|
» |
Gamma [Design Patterns-page <<1>>23]
|
^
inmediatamente después de un corchetes abierto para negar una
clase caracter: [^a-z] encaja con cualquier caracter que no es una
letra minúscula.
Algunas clases caracter son utilizadas tan frecuentemente que Ruby proporciona
abreviaturas para ellas. Esas abreviaturas son listadas en la tabla 5.1 de la página
59---deberían ser utilizadas dentro de corchetes y en el cuerpo de un patrón.
showRE('It costs $12.', /\s/)
|
» |
It<< >>costs $12.
|
showRE('It costs $12.', /\d/)
|
» |
It costs $<<1>>2.
|
Character class abbreviations
|
||||||||||||||||||||||||||||||
a = 'It costs $12.'
|
||
showRE(a, /c.s/)
|
» |
It <<cos>>ts $12.
|
showRE(a, /./)
|
» |
<<I>>t costs $12.
|
showRE(a, /\./)
|
» |
It costs $12<<.>>
|
/\s*\|\s*/, dijimos que queriamos encajar
una barra verticial rodeada por un conjunto arbitrario de espacios en blanco. Ahora sabemos que la secuencia \s encaja
un único caracter de espacio en blanco, así que parece como si los asteriscos de algún modo
significasen ``un número arbitrario.'' De hecho, el asterisco es uno de los varios
modificadores que permiten encajar múltiples ocurrencias de un patrón.
Si r se encuentra precediendo inmediatamente una expresión regualar dentro de un patrón, entonces:
r
*
|
encaja cero o más ocurrencias de r. |
r
+
|
encaja una o más ocurrencias de r. |
r
?
|
encaja cero o una ocurrencia de r. |
r
{m,n}
|
encaja al menos ``m'' y como máximo ``n'' ocurrencias de r. |
r
{m,}
|
encaja al menos ``m'' ocurrencias de r. |
/ab+/ encaja una ``a'' seguida por una o más ``b'',
uno una secuencia de ``ab''. Tienes que ser cuidadoso con el constructor también *---el patrón /a*/ encajará con cualquier cadena;
cadena tiene cero o más ``a''.
Esos patrones son llamados avariciosos,
porque por defecto encajarán la mayor parte de la cadena que puedan. Puedes alterar
este comportamiento, y entonces encajarán lo mínimo, añadiendo una interrogación como sufijo.
a = "The moon is made of cheese"
|
||
showRE(a, /\w+/)
|
» |
<<The>> moon is made of cheese
|
showRE(a, /\s.*\s/)
|
» |
The<< moon is made of >>cheese
|
showRE(a, /\s.*?\s/)
|
» |
The<< moon >>is made of cheese
|
showRE(a, /[aeiou]{2,99}/)
|
» |
The m<<oo>>n is made of cheese
|
showRE(a, /mo?o/)
|
» |
The <<moo>>n is made of cheese
|
a = "red ball blue sky"
|
||
showRE(a, /d|e/)
|
» |
r<<e>>d ball blue sky
|
showRE(a, /al|lu/)
|
» |
red b<<al>>l blue sky
|
showRE(a, /red ball|angry sky/)
|
» |
<<red ball>> blue sky
|
showRE('banana', /an*/)
|
» |
b<<an>>ana
|
showRE('banana', /(an)*/)
|
» |
<<>>banana
|
showRE('banana', /(an)+/)
|
» |
b<<anan>>a
|
a = 'red ball blue sky'
|
||
showRE(a, /blue|red/)
|
» |
<<red>> ball blue sky
|
showRE(a, /(blue|red) \w+/)
|
» |
<<red ball>> blue sky
|
showRE(a, /(red|blue) \w+/)
|
» |
<<red ball>> blue sky
|
showRE(a, /red|blue \w+/)
|
» |
<<red>> ball blue sky
|
showRE(a, /red (ball|angry) sky/)
|
» |
no match
|
a = 'the red angry sky'
|
||
showRE(a, /red (ball|angry) sky/)
|
» |
the <<red angry sky>>
|
\1 se refiere al encaje del primer grupo, \2 el segundo grupo y así. Fuera del patrón,
Fuera del patrón, las variables especiales
$1, $2, y demás, sirven para el mismo propósito.
"12:50am" =~ /(\d\d):(\d\d)(..)/
|
» |
0
|
"Hour is #$1, minute #$2"
|
» |
"Hour is 12, minute 50"
|
"12:50am" =~ /((\d\d):(\d\d))(..)/
|
» |
0
|
"Time is #$1"
|
» |
"Time is 12:50"
|
"Hour is #$2, minute #$3"
|
» |
"Hour is 12, minute 50"
|
"AM/PM is #$4"
|
» |
"AM/PM is am"
|
# match duplicated letter
|
||
showRE('He said "Hello"', /(\w)\1/)
|
» |
He said "He<<ll>>o"
|
# match duplicated substrings
|
||
showRE('Mississippi', /(\w+)\1/)
|
» |
M<<ississ>>ippi
|
showRE('He said "Hello"', /(["']).*?\1/)
|
» |
He said <<"Hello">>
|
showRE("He said 'Hello'", /(["']).*?\1/)
|
» |
He said <<'Hello'>>
|
/a.*b.*c.*d.*e/ and encontrar ``absconded'' y ``ambuscade.'' Eso tendría que ser
suficiente.
Sin embargo, hay veces en las que necesitas cambiar cosas basandoste en un patrón de encaje.
Volvamos a nuestro fichero con la lista de canciones. Quienquiera que lo creo
introdujo todos los nombres de artistas en minúsculas. Cuando los mostramos en la
pantalla de la jukebox, tendrían mejor aspecto en mayusculas y minúsculas.
¿Cómo podemos cambiar el primer carácter de cada palabra a mayúsculas?
Los métodos
String#sub
y
String#gsub
buscan una porción de
una cadena que encaje con su primeros argumentos y lo reemplaza con los segundos.
String#sub
realiza un reemplazo, mientras
String#gsub
reemplaza cada ocurrencia del encaje. Ambas rutinas
devuelven una nueva copia de String conteniendo las sustituciones.
Versiones mutadas
String#sub!
y
String#gsub!
modifican
la cadena original.
a = "the quick brown fox"
|
||
a.sub(/[aeiou]/, '*')
|
» |
"th* quick brown fox"
|
a.gsub(/[aeiou]/, '*')
|
» |
"th* q**ck br*wn f*x"
|
a.sub(/\s\S+/, '')
|
» |
"the brown fox"
|
a.gsub(/\s\S+/, '')
|
» |
"the"
|
String o un bloque. Si se utiliza un bloque,
el valor del bloque es sustituido dentro de
String.
a = "the quick brown fox"
|
||
a.sub(/^./) { $&.upcase }
|
» |
"The quick brown fox"
|
a.gsub(/[aeiou]/) { $&.upcase }
|
» |
"thE qUIck brOwn fOx"
|
\b\w---busca un límite de una palabra seguido por un caracter de palabra.
Combina esto con gsub y ya podemos solucionar los nombres de artistas.
def mixedCase(aName)
|
||
aName.gsub(/\b\w/) { $&.upcase }
|
||
end
|
||
|
||
mixedCase("fats waller")
|
» |
"Fats Waller"
|
mixedCase("louis armstrong")
|
» |
"Louis Armstrong"
|
mixedCase("strength in numbers")
|
» |
"Strength In Numbers"
|
\1, \2,
y demás estan disponibles en el patrón,
available in the pattern, representando el enesimo grupo encajado hasta ahí. Las mismas secuencias están disponibles
en el segundo argumento de sub y gsub.
"fred:smith".sub(/(\w+):(\w+)/, '\2, \1')
|
» |
"smith, fred"
|
"nercpyitno".gsub(/(.)(.)/, '\2\1')
|
» |
"encryption"
|
\& (ultima coincidencia), \+ (ultima coincidencia de grupo),
\` (cadena previamente encajada), \' (cadena tras el encaje), y
\\ (barra invertida literal).
Se vuelve confuso si quieres incluir una barra invertida litera en una sustitución. La manera obvia es escribir
str.gsub(/\\/, '\\\\') |
str
por dos. El programador duplica las barras inverdiad en el texto de reemplazo, sabiendo que
ellas serán convertidas en ``\\'' en el analisis de sintaxis. Sin embargo, cuando la sustitución sucede,
el motor de expresión regular realiza otra pasada por la cadena, convirtiendo
``\\'' en ``\'', así que el efecto red es reemplazar cada barra invertida con otra barra invertida. Tienes que escribir
gsub(/\\/, '\\\\\\\\')!
str = 'a\b\c'
|
» |
"a\b\c"
|
str.gsub(/\\/, '\\\\\\\\')
|
» |
"a\\b\\c"
|
\& es reemplazado con la cadena encajada, podrías escribir
str = 'a\b\c'
|
» |
"a\b\c"
|
str.gsub(/\\/, '\&\&')
|
» |
"a\\b\\c"
|
gsub, la cadena para sustitución es
analizada una única vez (durante la pasada de sintaxis) y el restuado es el que tu pretendías.
str = 'a\b\c'
|
» |
"a\b\c"
|
str.gsub(/\\/) { '\\\\' }
|
» |
"a\\b\\c"
|
def unescapeHTML(string)
str = string.dup
str.gsub!(/&(.*?);/n) {
match = $1.dup
case match
when /\Aamp\z/ni then '&'
when /\Aquot\z/ni then '"'
when /\Agt\z/ni then '>'
when /\Alt\z/ni then '<'
when /\A#(\d+)\z/n then Integer($1).chr
when /\A#x([0-9a-f]+)\z/ni then $1.hex.chr
end
}
str
end
puts unescapeHTML("1<2 && 4>3")
puts unescapeHTML(""A" = A = A")
|
1<2 && 4>3 "A" = A = A |
Regexp (documentado comenzando en la página
361).
re = /cat/
|
||
re.type
|
» |
Regexp
|
Regexp#match
encaja una expresión regular con una cadena. Si no tiene éxito, devuelve
nil. Si tiene éxito, devuelve una instancia de la clase MatchData, cuya documentación comienza en la página 336.
Y ese objeto MatchData te da acceso a toda la información disponible sobre el encaje. Todo lo interesante que
puedes coger de las variables-$ está empaquetado en este manejable objeto.
re = /(\d+):(\d+)/ # match a time hh:mm
|
||
md = re.match("Time: 12:34am")
|
||
md.type
|
» |
MatchData
|
md[0] # == $&
|
» |
"12:34"
|
md[1] # == $1
|
» |
"12"
|
md[2] # == $2
|
» |
"34"
|
md.pre_match # == $`
|
» |
"Time: "
|
md.post_match # == $'
|
» |
"am"
|
Regexp contra dos cadenas. Cada encaje
devuelve un único objeto MatchData, el cual nosotros verificamos
examinando los dos campos subpatrón.
re = /(\d+):(\d+)/ # match a time hh:mm
|
||
md1 = re.match("Time: 12:34am")
|
||
md2 = re.match("Time: 10:30pm")
|
||
md1[1, 2]
|
» |
["12", "34"]
|
md2[1, 2]
|
» |
["10", "30"]
|
nil o un objeto MatchData) en una variable de hebra local (accesible utilizando $~).
Todas las otras variables de expresion regular son entonces derivados de este objeto. Aunque no podemos
realmente pensar en un uso para el siguiente código, demuestra que todos las otras variables-$ MatchData son
de hecho esclavas del valor en $~.
re = /(\d+):(\d+)/
|
||
md1 = re.match("Time: 12:34am")
|
||
md2 = re.match("Time: 10:30pm")
|
||
[ $1, $2 ] # last successful match
|
» |
["10", "30"]
|
$~ = md1
|
||
[ $1, $2 ] # previous successful match
|
» |
["12", "34"]
|
MatchData.
Para el uso diario, ellos las encuentra más convenientes. Algunas veces no podemos ayudar siendo pragmáticos.