|
|||
Forrige < |
Innhold ^
|
Neste >
|
Fixnum
.
Heltall utenfor denne mengden lagres som objekter av klassen Bignum
(som for tiden er implementert som et sett short heltall med variabel lengde). Ruby tar seg av konverteringen fram og tilbake mellom disse typene automatisk.
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
for oktalt, 0x
for heksidesimalt, eller
0b
for binært), fulgt av en streng med sifre utifra grunntallet.
Understrekningstegn i sifferstrengen ignoreres.
123456 # Fixnum 123_456 # Fixnum (understrekning ignoreres) -543 # negativ Fixnum 123_456_789_123_345_789 # Bignum 0xaabb # heksadesimal 0377 # oktal -0b101_010 # binær (negetert) |
value & 0x9f
''.
Meta-versjonen av en verdi er
``value | 0x80
''.
Til sist lager sekvensen ?\C-? et ASCII delete-tegn, 0177
.
?a # tegn kode ?\n # kode for en lineskift (0x0a) ?\C-a # control a = ?A & 0x9f = 0x01 ?\M-a # meta setter bit 7 ?\M-\C-a # meta og control a ?\C-? # delete tegn |
Float
-objekt, som tilsvarer den underliggende arkitekturens
double
datatype. Etter desimaltegnet må det følge et siffer, siden 1.e3
vil forsøke å kalle metoden e3
i klassen Fixnum
.
Alle tall er objekter og motta en rekke forskjellige meldinger (komplett liste starter på sidene 290, 313, 323 og 349(??)). Dermed finner du absoluttverdien til et tall ved å skrive
aNumber.abs
og ikke abs(aNumber)
, slik som i (for eksempel) C++.
Heltall støtter også en rekke nyttige iteratorer. Vi har alt sett en---7.times
i kodeeksempelet på side 47(??).
Blant de andre finner vi upto
og
downto
, som itererer opp og ned mellom to heltall, og
step
, som ligner mer på en tradisjonell for
-løkke.
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 # del linjen og lagr elementene i val print vals[0] + vals[1], " " end |
3 4 5 6 7 8 |
String#to_i
metoden for å gjøre strengen om til et heltall først.
DATA.each do |line| vals = line.split print vals[0].to_i + vals[1].to_i, " " end |
7 11 15 |
String
.
Strenger lages ofte ved hjelp av strenglitteraler---sekvenser av tegn mellom skilletegn.
Siden binær data er vanskelig å representere inne i kildekode, kan du bruke forskjellige escape-sekvenser i en strenglitteral. Hver enkelt av dem byttes ut med den tilsvarende binære verdien når programmet kompileres. Valget av type skilletegn bestemmer hvor mye som byttes ut under kompilering. I strenger hvor apostrof (') brukes som skilletegn, blir to påfølgende bakvendte skråstreker til en og en enkelt bakvendt skråstrek fulgt av en apostrof blir til bare en apostrof.
'escape using "\\"'
|
» |
escape using "\"
|
'That\'s right'
|
» |
That's right
|
#{
expr }
.
Hvis uttrykket bare er en global, klasse- eller instansvariabel, kan du droppe klammeparentesene.
"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
, og ``here dokumenter.''
%q
og %Q
starter apostrof og kråketær adskilte strenger.
%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 |
<<
tegnene.
Normalt må denne terminerende strengen starte i første kolonne, men hvis du legger til et minustegn etter <<
tegnene, kan du indentere den.
print <<-STRING1, <<-STRING2 Concat STRING1 enate STRING2 |
Concat enate |
String
er sannsynligvis den største av Ruby sine innebygde klasser, med over 75 standard metoder. Vi vil ikke gå igjennom alle her; bibliotekreferansen har en fullstendig liste. Men vi vil se på noen vanlige bruksmåter---bruksmåter som sannsynligvis vil dukke opp under den daglige programmeringen.
Tilbake til jukeboksen. Selv om den er ment å være tilknyttet Internet,
beholder den også kopier av noen populære sanger på en lokal harddisk. Dette gjør at vi kan
underholde kundene våre til tross for at et ekorn spiser i stykker nettverkskoblingen vår eller lignende.
Av historiske grunner (finnes det noen andre typer?), lagres listen av sanger som rader i en flat fil. Hver rad består av navnet på filen som inneholder selve sangen, sangens lengde, artistens navn og tittelen. Alt dette i felter separert av vertikale streker. En fil kunne for eksempel begynne slik:
/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
-klassens mange metoder for å hente ut og omforme feltene før vi lager Song
-objekter utifra dem. Om ikke annet, må vi:
String#split
klare fint for oss.
I dette tilfellet gir vi split
metoden et regulært uttrykk,
/\s*\|\s*/
, som deler linjen opp ved hver vertikal strek den finner,
eventuelt med et eller flere mellomrom på begge sider.
Videre trenger vi å fjerne linjeskifttegnet på slutten av linjen, så vi bruker
String#chomp
for å fjerne det rett før vi kaller 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
,
som reduserer rekker av gjentatte tegn ned til bare et tegn.
Vi vil benytte oss av squeeze!
versjonen som endrer selve strengobjektet.
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
metoden nok en gang, og denne gangen dele tidsfeltet opp rundt kolontegnet.
mins, secs = length.split(/:/) |
String#scan
ligner på split
i det at den også deler en streng opp i delstrenger basert på et mønster. Men i motsetning til split
, gir du
scan
det mønsteret du ønsker at delstrengene skal oppfylle.
I dette tilfellet ønsker vi at et eller flere sifre for både minutt- og sekunddelen. Mønsteret for et eller flere sifre er /\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| # trekk ut hvert enkelt ord 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
henter ut elementer fra en streng utifra et regulært uttrykk. I dette tilfellet er det mønsteret ``\w[-\w']+
'' som fanger opp enhver bokstav , fulgt av en eller flere av det som spesifiseres i hakeparentesene(bindestrek, en annen bokstav eller en apostrof).
Vi vil gå dypere inn på regulære uttrykk på side 56(??).
For å få søket til å ignorere om bokstavene er små eller store, gjør vi alle ordene vi henter ut, eller bruker som søkenøkler, om til små bokstaver.
Legg merke til utropstegnet på slutten av det første downcase!
metodenavnet. Som med squeeze!
vi brukte tildigere, angir utropstegnet at selve objektet endres, i dette tilfellet blir store bokstaver om til små.
[
Det er en liten feil i dette eksempelet: sangen ``Gone, Gone, Gone'' ville
blitt indeksert tre ganger. Kan du tenke ut en løsning?
]
La oss utvide SongList
klassen til å indeksere sangene underveis når de legges til og legge til en metode for å finne en sang utifra et ord.
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
. Men la oss heller ta en titt på en enklere datatype: rekker.
1..10 'a'..'z' 0...anArray.length |
Range
-objekt som inneholder referanser til to
Fixnum
-objekter.
Hvis du trenger å omdanne en rekke til en liste, kan du bruke
to_a
metoden.
(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
kalles og objektene må kunne sammenlignes med <=>
, den generelle sammenligningsoperatoren.
Denne operatoren, <=>
som gjerne kalles romskipoperatoren, returnerer -1, 0 eller +1 alt etter om det første argumentet er mindre enn, lik eller større enn det andre argumentet.
Her er en enkel klasse som representerer rader med ``#'' tegn,
som vi kunne bruke som en tekstbasert løsning når vi tester
volumkontrollen til jukeboksen.
class VU include Comparable attr :volume def initialize(volume) # 0..9 @volume = volume end def inspect '#' * @volume end # Støtte av rekker def <=>(other) self.volume <=> other.volume end def succ raise(IndexError, "Volume too big") if @volume >= 9 VU.new(@volume.succ) end end |
VU
-objekter.
medium = VU.new(4)..VU.new(7)
|
||
medium.to_a
|
» |
[####, #####, ######, #######]
|
medium.include?(VU.new(3))
|
» |
false
|
while gets print if /start/../end/ end |
===
operatoren, også kalt case equality operator.
(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*/)
slår ut på en vertikal strek med eventuelle mellomrom på hver side. Vi vil nå dykke dypere ned i detaljene til regulære uttrykk og vise hvorfor det er slik.
Regulære uttrykk brukes for å gjenfinne mønstre i strenger.
Ruby har innebydt støtte som gjør mønstergjenkjenning og -substitusjon enkelt og konsist. I denne delen vil vi gå igjennom alle hovedegenskapene til regulære uttrykk. Noen detaljer vil vi hoppe over: titt på side 205(??) for mer informasjon.
Regulære uttrykk er objekter av klassen Regexp
.
De kan lages ved å eksplisitt kalle konstruktøren eller ved å skrive litteraler slik som /pattern/ og %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)
eller operatorene =~
(positiv match) og !~
(negativ match) for å se om en streng inneholder noe
som passer inn i mønsteret.
Disse match-operatorene er definert for både String
og Regexp
. Hvis begge operandene er strenger, blir den høyre omdannet til et regulært uttrykk.
a = "Fats Waller"
|
||
a =~ /a/
|
» |
1
|
a =~ /z/
|
» |
nil
|
a =~ "ll"
|
» |
7
|
$&
, biten før ender opp i $`
og restene av strengen går til $'
. Vi kan bruke dette for å skrive en metode, showRE
,
som illustrerer hvor et mønster slår ut.
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
|
$~
og
$1
til og med $9
.
$~
er et MatchData
-objekt (beskrivelse starter på side 336(??)) som inneholder alt du kan ønske å vite om
mønstersammenligningen. Variablene $1
og utover holder verdiene til deler av sammenligningen. Vi kommer inn på disse senere. For de av dere som får noia av å se slike Perl-lignende variabelnavn, ikke gå ennå. Vi har gode nyheter på slutten av kapittelet.
showRE('kangaroo', /angar/)
|
» |
k<<angar>>oo
|
showRE('!@%&-_=+', /%&/)
|
» |
!@<<%&>>-_=+
|
/\s*\|\s*/
. \|
betyr ``gjenkjenn en vertikal strek.'' Uten den bakvendte skråstreken, ville
``|
'' betyd veksling (som vi beskriver senere).
showRE('yes | no', /\|/)
|
» |
yes <<|>> no
|
showRE('yes (no)', /\(no\)/)
|
» |
yes <<(no)>>
|
showRE('are you sure?', /e\?/)
|
» |
are you sur<<e?>>
|
#{...}
.
/iss/
opp mot strengen ``Mississippi,'' og den vil finne substrengen ``iss'' som starter på posisjon en. Men hva om du vil tvinge et mønster til kun å slå til på begynnelsen eller slutten av en streng?
Mønstrene ^
og $
tilsvarer begynnelsen og slutten på en linje.
Disse brukes ofte for å ankerfeste et mønster: for eksempel vil
/^option/
kun slå ut hvis ordet ``option'' er på begynnelsen
av linjen.
Sekvensen \A
slår ut på begynnelsen av en streng, og \z
og \Z
slår ut på slutten av en streng. (Faktisk, så slår \Z
ut på slutten av strengen med mindre strengen slutter med en ``\n'', i hvilket tilfelle \Z
slår ut på rett før linjeskifttegnet.)
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
og \B
ut på grensene mellom ord og ikke-ord, respektivt. Med ord mener vi her bokstaver, tall og understrekningstegn.
showRE("this is\nthe time", /\bis/)
|
» |
this <<is>>\nthe time
|
showRE("this is\nthe time", /\Bis/)
|
» |
th<<is>> is\nthe time
|
[
tegn
]
slår ut på envher av tegnene mellom hakeparentesene. [aeiou]
vil slå ut på en (engelsk) vokal,
[,.:;!?]
slår ut på tegnsetting og så videre.
Betydningen av spesielle tegn i regulære
uttrykk---.|()[{+^$*?
---er slått av på innsiden av hakeparentesene.
Men normal strengsubstitusjon fungerer fremdeles, så
\b
tilsvarer et backspace-tegn, \n
et linjeskift og så videre (se tabell 18.2 på side 203(??)).
I tillegg kan du bruke forkortelsene fra tabell 5.1 på side 59(??), slik at \s
betyr hvilket som helst tegn som gir luft i teksten og ikke bare mellomromtegnet.
showRE('It costs $12.', /[aeiou]/)
|
» |
It c<<o>>sts $12.
|
showRE('It costs $12.', /[\s]/)
|
» |
It<< >>costs $12.
|
]
og -
i en tegnklasse, må de stå i begynnelsen.
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]
|
^
-tegn rett etter den åpnende hakeparentesen for å negere tegnklassen: [^a-z]
slår ut på enhver bokstav som ikke er en liten bokstav.
Noen tegnklasser er så vanlig brukt at Ruby tilbyr forkortelser for dem.
Disse forkortelsene finner du i tabell 5.1 på side 59(??)---de kan brukes både inne i hakeparenteser og i selve mønsterkroppen.
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*/
, sa vi at vi ønsket å finne en vertikal strek omringet av vilkårlig mellomromstegn. Vi vet nå at \s
tilsvarer et mellomromstegn, så da virker det logisk dersom stjernen betyr ``en vilkårlig mengde''. Det stemmer, stjerne er en av flere modifikatorer som lar deg slå ut på gjentakelser av et mønster.
Hvis r står for den delen av det regulære uttrykket som er rett før, så vil:
r
*
|
tilsvare null eller flere gjentagelser av r. |
r
+
|
tilsvare en eller flere gjentagelser av r. |
r
?
|
tilsvare null eller en utgave av r. |
r
{m,n}
|
tilsvare minst ``m'' og maksimum ``n'' gjentagelser av r. |
r
{m,}
|
tilsvare minst ``m'' gjentagelser av r. |
/ab+/
tilsvarer en ``a'' fulgt av en eller flere ``b''-tegn,
og ikke flere gjentagelser av strengen ``ab'' .
Du bør være forsiktig med *
---mønsteret /a*/
vil slå ut på enhver streng; absolutt alle strenger har jo null eller flere ``a''-tegn.
Man sier gjerne at disse mønstrene er grådige, da de til vanlig
slår ut på så mye av strengen som mulig.
Du kan gjør dem sparsommelige og få dem til å slå ut på minst mulig, ved å legge til et spørsmålstegn på slutten.
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
resultatet fra første gruppering,
\2
fra andre og så videre.
Utenfor mønsteret gjør spesialvariablene $1
, $2
og så videre, samme nytte.
"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/
og funnet ``absconded'' og ``ambuscade.''
Det må da være verdt et eller annet.
Men av og til ønsker du å endre strengen utifra det som mønsteret gjenkjenner.
La oss ta steget tilbake til vår fil med sanglisten. Den som skrev filen la inn alle artistnavnene med små bokstaver. Når vi viser dem frem på skjermen til jukeboksen, vil de sett bedre ut med stor forbokstav. Hvordan kan vi gjør den første bokstaven i hvert ord stor?
...
Metodene
String#sub
og
String#gsub
ser etter en porsjon av en streng som passer med deres første argument og bytter det ut med det som er i det andre argumentet.
String#sub
gjør bare en substitusjon, mens
String#gsub
bytter ut alle forekomster av mønsteret. Begge rutinene returnerer en ny kopi av String
-objektet med endringene. Mutatorversjonene
String#sub!
og
String#gsub!
endrer den opprinnelige strengen.
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"
|
a = "the quick brown fox"
|
||
a.sub(/^./) { $&.upcase }
|
» |
"The quick brown fox"
|
a.gsub(/[aeiou]/) { $&.upcase }
|
» |
"thE qUIck brOwn fOx"
|
\b\w
---se for en grense mellom ord fulgt av en bokstav.
Kombinert dette med gsub
og vi kan enkelt endre artistenes navn.
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
, og så videre er tilgjengelig i mønsteret, og inneholder det nte resultatet fra en gjenkjent gruppering så langt. Disse sekvensene er også tilgjengelig i det andre argumentet til sub
og gsub
.
"fred:smith".sub(/(\w+):(\w+)/, '\2, \1')
|
» |
"smith, fred"
|
"nercpyitno".gsub(/(.)(.)/, '\2\1')
|
» |
"encryption"
|
\&
(forrige gjenkjente), \+
(forrige gjenkjente gruppe),
\`
(delen av strengen før treffet),
\'
(delen av strengen etter treffet) og
\\
(en litteral bakvendt skråstrek)
Det kan lett bli litt forvirrende hvis du ønsker å inkludere en bakvendt skråstrek i en substitusjon. Den åpenbare løsningen er å skrive:
str.gsub(/\\/, '\\\\') |
\\
'' under den syntaktiske analysen.
Men, når selve substitusjonen tar seg, kjører rutinene for regulære uttrykk nok en tur igjennom strengen og gjør ``\\
'' om til ``\
'', slik at den totale effekten er å bytte ut en enkelt backslash med en annen enkel backslash. Du må i stedet skrive
gsub(/\\/, '\\\\\\\\')
!
str = 'a\b\c'
|
» |
"a\b\c"
|
str.gsub(/\\/, '\\\\\\\\')
|
» |
"a\\b\\c"
|
\&
blir byttet ut med den delstrengen som ble gjenkjent, og skrevet
str = 'a\b\c'
|
» |
"a\b\c"
|
str.gsub(/\\/, '\&\&')
|
» |
"a\\b\\c"
|
gsub
, blir strengen som skal substitueres inn analysert kun en gang (under den syntaktiske analysen) og resultatet blir som forventet.
str = 'a\b\c'
|
» |
"a\b\c"
|
str.gsub(/\\/) { '\\\\' }
|
» |
"a\\b\\c"
|
case
uttrykket, som vi starter å omtale på side 81(??).
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
(dokumentasjonen starter på side 361(??)).
We've already come across one class: regular expression literals
create instances of class Regexp
(documented beginning on page
361).
-->
re = /cat/
|
||
re.type
|
» |
Regexp
|
Regexp#match
forsøker å gjenkjenne et regulært uttrykk i en streng. Hvis den ikke klarer det, returneres nil
. Hvis den klarer det, returneres en instans av klassen MatchData
, som dokumenteres på side 336(??) og utover.
Dette MatchData
-objektet gir deg tilgang til all
tilgjengelig informasjon om gjenkjenningen. Alt det snadderet du kan få ut av $-variablene er samlet i et lite, hendig objekt.
re = /(\d+):(\d+)/ # gjenkjenn et tidspunkt 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
-objektet på to strenger. Hver sammenligning returnerer en et unikt
MatchData
-objekt, som vi verifiserer at er riktig, ved å titte i feltene for de to submønstrene.
re = /(\d+):(\d+)/ # gjenkjenn et tidspunkt 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
eller et MatchData
-objekt)
i den tråd-lokale variabelen $~
.
Alle de andre variablene for regulære uttrykk utledes så fra dette objektet.
Selv om vi ikke klarer å komme på en fornuftig bruk av den følgende koden, demonstrerer den i det minste alle de andre $-variablene relatert til MatchData
-objektet faktisk hentes fra verdien i $~
.
re = /(\d+):(\d+)/
|
||
md1 = re.match("Time: 12:34am")
|
||
md2 = re.match("Time: 10:30pm")
|
||
[ $1, $2 ] # siste vellykkede gjenkjenning
|
» |
["10", "30"]
|
$~ = md1
|
||
[ $1, $2 ] # forrige vellykkede gjenkjenning
|
» |
["12", "34"]
|
MatchData
-objekter. Til daglig bruk er og blir de den mest beleielige løsningen.
Noen ganger kan vi ikke stoppe oss selv fra å være pragmatiske.
( In progress translation to Norwegian by NorwayRUG. $Revision: 1.15 $ )
Forrige < |
Innhold ^
|
Neste >
|