[RegEx] Replacen mbv backreferences op een goede manier?

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • n2k
  • Registratie: December 2004
  • Laatst online: 17-09 20:17
Hey mensen,

Ik zit met een probleempje. Ik wil met regex l(kleine letter L) in I(hoofdletter i) veranderen op de goede plekken :)
Ik ben zover gekomen dat ik alle situaties in een bestand te pakken kan krijgen, nu moet ik de kleine letter L alleen nog zien te vervangen.

Hij gaat elke match (verdeeld door middel van pipes(or)) die hij vind vervangen met hoofdletter i. Wat niet goed is, ik wil dat hij alleen match1 op de manier van replacement1 vervangt, etc.

Hopelijk word het wat duidelijker met een voorbeeldje:
----- De regex code -----
(([\s])l([ftns,\'\s]))|((\. )l)|((\d\r\n)l)


----- stukje tekst -----
35
00:03:33,179 --> 00:03:35,90[u][b]9
l[/b][/u]t's my business how[u][b] l [/b][/u]spend
the money that[u][b] l [/b][/u]make!


----- backreferences ( spaties aangegeven met een underscore '_' ) -----
totaal1234567
9\r\nl 9\r\nl9\r\n
_l__l___
_l__l___


----- Replacing met backreferences -----
\2I\3\5I\7I


----- Resultaat (overbodige grote i's zijn bold) -----
35
00:03:33,179 --> 00:03:35,90[b]II[/b]9
It's my business how I [b]II[/b]spend
the money that I [b]II[/b]make!


Wat ik dus nu heb zijn de situaties waar de kleine L voor een grote i vervangen moet worden.
Zelf stuit ik op de volgende mogelijkheden:
  1. Ik verteld de backreferences op één of andere manier dat ze maar één keer 'hun eigen match' vervangen met een grote i.
  2. Ik kan de rest van de lines ook opvangen dmv regex zonder de resultaten te beïnvloeden en plak ze daarna met backreferences aan elkaar (en uiteraard de kleine L's voor grote i's vervangen)
In beide gevallen heb ik zelf nog geen succes gehad. Ik heb geprobeerd met php de matches af te vangen en dus match1 vervangt voor replacement1, maar stuit ik alsnog op probleem nummer 2 :'(
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
preg_match_all('/(([\s])l([ftns,\'\s]))|((\. )l)|((\d\r\n)l)/', $contents, $result, PREG_SET_ORDER);
for ($matchi = 0; $matchi < count($result); $matchi++) {
    for ($backrefi = 0; $backrefi < count($result[$matchi]); $backrefi++) {
        if($result[$matchi][1] != "") {
            echo $result[$matchi][2]."I".$result[$matchi][3];
        }
        elseif($result[$matchi][4] != "") {
            echo $result[$matchi][5]."I";
        }
        elseif($result[$matchi][6] != "") {
            echo $result[$matchi][7]."I";
        }
    } 
}


Hoe ga ik dit oplossen :?
PS. als je denkt jeetje wat doet hij nou dom, zeg 't gewoon en laat zien hoe jij het makkelijker zou doen :p

Acties:
  • 0 Henk 'm!

  • benoni
  • Registratie: November 2003
  • Niet online
Je hebt 3 x de 'I' (letter i) in de vervangtekst staan, terwijl je daar geen of-of keuzes kunt aangeven zoals je met de '|' (divider) markeert in de expressie zelf. Op zich is was je er bijna met je oplossing, je kunt in dit geval de mogelijke backreferences gewoon achter elkaar stapelen in de output als je maar zorgt dat de ze aan de goede kant komen te staan van de vervangende letter i. Ik heb het geheel iets simpeler geschreven:

zoeken:
code:
1
([\s])l([ftns,\'\s])|(\. )l|(\d\r\n)l


vervangen:
code:
1
\1\3\4I\2


Bij sommige programma's kun je in de vervangtekst trouwens ook \U gebruiken voor uppercase en \E om dat weer af te sluiten. Dat kan nog wel eens handig zijn als het een keer niet alleen om de i's gaat. Dan kun je dus \U\1\E\2 als je \1 als backreference wilt omzetten naar hoofdletters en de rest (\2) niet. Bij PHP gaat dat niet met zo'n code, maar je kunt een functie als strtoupper() erin hangen. Zie verder de aanwijzingen op php.net :)

[ Voor 60% gewijzigd door benoni op 17-01-2009 21:59 ]


Acties:
  • 0 Henk 'm!

Verwijderd

Ik zou met zoiets aan de gang gaan:
PHP:
1
2
3
4
5
6
7
8
9
10
11
$out = preg_replace (
   array (
      '~l(([ftns]|t\'s)\s+)~',
      '~\bl\b~'
   ),
   array (
      'I\\1',
      'I'
   ),
   $in
);

Let op, er zal wel niet veel wan kloppen, maar het is een begin. Het lijkt me veel eenvoudiger dan wat jij aan het doen was. Overigens gaat dit je niet echt op deze manier lukken, tenzij het écht beperkt is tot "i", "if", "it" etcetera. Feitelijk heb je gewoon verkeerd gespelde woorden. Als het om i's gaat aan het begin van woorden, kun je met het volgende een eind komen, want een l aan het begin van een woord wordt meestal gevolgd door een klinker:
PHP:
1
$out = preg_replace ( '~\b(?<!\')l(?=[^aeiouy])~', 'I', $in );

Het vereist natuurlijk wel veel testwerk.

Acties:
  • 0 Henk 'm!

  • n2k
  • Registratie: December 2004
  • Laatst online: 17-09 20:17
benoni schreef op zaterdag 17 januari 2009 @ 20:55:
zoeken:
code:
1
([\s])l([ftns,\'\s])|(\. )l|(\d\r\n)l\r


vervangen:
code:
1
\1\3\4I\2
Je code werkt super, alleen omdat je \r op het eind heb toegevoegd (waarom trouwens :?) pakt hij geen woorden aan het begin van een regel na een tijdscode.

165
00:13:50,262 --> 00:13:51,564
ldiot!


Als ik em weg haal, blijf ik al m'n resultaten houden, of als ik |(\d\r\n)l erachter plak doet ie 't ook (maar das dubbelop)
Dus nogmaals bedankt voor je oplossing en zou je even kunnen uitleggen wat die \r op het eind doet? :)

----
bedankt voor je suggestie cheatah, alleen ik hou niet zo van testen :p

[ Voor 5% gewijzigd door n2k op 17-01-2009 21:35 ]


Acties:
  • 0 Henk 'm!

Verwijderd

Mijn tweede suggestie doet dat wel goed. En je hoeft mijn regular expression niet te testen, je hoeft alleen maar te kijken of het doet wat het moet doen, niet meer en niet minder.

Acties:
  • 0 Henk 'm!

  • benoni
  • Registratie: November 2003
  • Niet online
n2k schreef op zaterdag 17 januari 2009 @ 21:32:
Je code werkt super, alleen omdat je \r op het eind heb toegevoegd (waarom trouwens :?) pakt hij geen woorden aan het begin van een regel na een tijdscode.
Die is er onbedoeld ingeslopen denk ik :P

De array-als-input oplossing van Cheatah is wel een goed aanvullend idee voor als je de backreferences niet zomaar kunt opstapelen (bijvoorbeeld als de toegevoegde vervangende tekst verschillend moet zijn). Je knipt dan het probleem domweg op in verschillende regexpen, voor het onderhouden van de code is dat wel makkelijker want het ziet er wat overzichtelijker uit.
Pagina: 1