Tja, beetje brakke titel, weet bij GoT niet hoe ik het anders in 1 zin moet samenvatten.
Het probleem:
Ik heb een bestand (een joekel mag ik wel zeggen) met data. Platte ASCII file. Daarin zitten records van 320 tekens lang. Maar wel allemaal achter elkaar, zonder carriage returns en dergelijke. Dus 1 hele lange string:
*blabla...bla*blabla...bla*blabla...bla
Nu begint ieder record met een "*", maar in de records zelf kunnen ook sterretjes zitten.
Het bestand wil ik nu (voorlopig, er moet nog meer mee gebeuren) "converteren". Ik wil de records (320 tekens ieder dus) scheiden met een CrLf. Dus de uiteindelijke file moet er zo uit zien:
*blabla....bla
*blabla....bla
*blabla....bla
Mijn idee/redenatie:
Omdat het soms om grote, soms om kleine bestanden gaat wil ik niet ieder record apart lezen. Ik lees heel het bestand in een string in 1 klap. Nu deed ik eerst een replace(myString,"*",vbCrLf) om de records te scheiden. Werkt (hoewel soms wat traag) prima. Maar: in de records kunnen ook sterretjes voorkomen. Die wil ik dus niet perongeluk replacen.
Als het om een éénmalige conversie ging, dan las ik het wel netjes in stapjes van 320 bytes in een string en outputte ik die weer. Maar deze conversie moet vaak en veel uitgevoerd worden op bestanden variërend van 300Kb tot 76Mb.
Een bestand van 76Mb in 1 klap in een string lezen is geen probleem (als je de code wil hebben wil ik 'm wel posten, maar ik ben niet op zoek naar posts/commentaar hierover).
De replace wil alleen nog wel eens eruit klappen op een 76Mb string (out of string space)...Wiedes. Maar ook in blokken van 4Mb of 10Mb of whatever kan ik mijn probleem oplossen. Gaat het hier ook niet om.
Ik wil naar een regular expression toe. Eentje die een * matched, dan 319 tekens verder leest en dan weer een * matched.
Ik wil dus mijn string in die regex frotten, regex.replace erop los laten en dan het resultaat wegschrijven.
Mijn "test" code:
Om dit idee te testen heb ik even wat code in elkaar geflanst. Zie hier:
En de aanroep:
Wat dit zou moeten doen:
Tja...zou moeten...Wat ik graag zou willen
: Zoals ik mijn regex pattern nu heb geschreven lees ik er (volgens de regex help) het volgende:
"match een * en 4 willekeurige (non)whitespace tekens
Even uitgesplitst, zoals ik het redeneer:
• \* --> Match een sterretje (\ is escape teken)
• [(\s|\S)] --> Match een whitespace, tab etc (\s) of (|) een non-whitespace (\S)
• {4} --> en dat 4 tekens lang
Dat zou dus betekenen dat als ik mijn functie aanroep zoals in gegeven voorbeeld ik terug zou moeten krijgen: @D*it is@een test*bl@aat
Zoals je ziet verwacht ik dus alleen * gereplaced op plaatsen waar de positie een veelvoud van 4 is (later dus 320).
Wat ik echter terug krijg is het volgende: @ is@test@at
Alle sterretjes vervangen of foetsie...
Korte samenvatting
Hoe kan ik in een string alleen tekens op een bepaalde positie (veelvoud van x, dus op b.v. iedere 320-ste positie) vervangen door een ander teken? En hoe schrijf ik dat regex pattern dan?
/me Waarschuwing: Lees alsjeblieft goed de post voordat je met suggesties komt, ik probeer deze draad "zo schoon mogelijk" te houden.
...en ondertussen stoei ik even verder op zoek naar de oplossing
Het probleem:
Ik heb een bestand (een joekel mag ik wel zeggen) met data. Platte ASCII file. Daarin zitten records van 320 tekens lang. Maar wel allemaal achter elkaar, zonder carriage returns en dergelijke. Dus 1 hele lange string:
*blabla...bla*blabla...bla*blabla...bla
Nu begint ieder record met een "*", maar in de records zelf kunnen ook sterretjes zitten.
Het bestand wil ik nu (voorlopig, er moet nog meer mee gebeuren) "converteren". Ik wil de records (320 tekens ieder dus) scheiden met een CrLf. Dus de uiteindelijke file moet er zo uit zien:
*blabla....bla
*blabla....bla
*blabla....bla
Mijn idee/redenatie:
Omdat het soms om grote, soms om kleine bestanden gaat wil ik niet ieder record apart lezen. Ik lees heel het bestand in een string in 1 klap. Nu deed ik eerst een replace(myString,"*",vbCrLf) om de records te scheiden. Werkt (hoewel soms wat traag) prima. Maar: in de records kunnen ook sterretjes voorkomen. Die wil ik dus niet perongeluk replacen.
Als het om een éénmalige conversie ging, dan las ik het wel netjes in stapjes van 320 bytes in een string en outputte ik die weer. Maar deze conversie moet vaak en veel uitgevoerd worden op bestanden variërend van 300Kb tot 76Mb.
Een bestand van 76Mb in 1 klap in een string lezen is geen probleem (als je de code wil hebben wil ik 'm wel posten, maar ik ben niet op zoek naar posts/commentaar hierover).
De replace wil alleen nog wel eens eruit klappen op een 76Mb string (out of string space)...Wiedes. Maar ook in blokken van 4Mb of 10Mb of whatever kan ik mijn probleem oplossen. Gaat het hier ook niet om.
Ik wil naar een regular expression toe. Eentje die een * matched, dan 319 tekens verder leest en dan weer een * matched.
Ik wil dus mijn string in die regex frotten, regex.replace erop los laten en dan het resultaat wegschrijven.
Mijn "test" code:
Om dit idee te testen heb ik even wat code in elkaar geflanst. Zie hier:
Visual Basic 6:
1
2
3
4
5
6
7
8
9
10
11
| Private Function RegTest(sTMP As String, sReplStr As String) As String Dim objRE As Object Set objRE = CreateObject("VBScript.RegExp") objRE.IgnoreCase = True objRE.Global = True objRE.Pattern = "\*[(\s|\S)]{4}" objRE.IgnoreCase = True RegTest = objRE.Replace(sTMP, sReplStr) Set objRE = Nothing End Function |
En de aanroep:
Visual Basic 6:
1
| Debug.Print RegTest("*D*it is*een test*bl*aat", "@") |
Wat dit zou moeten doen:
Tja...zou moeten...Wat ik graag zou willen
"match een * en 4 willekeurige (non)whitespace tekens
Even uitgesplitst, zoals ik het redeneer:
• \* --> Match een sterretje (\ is escape teken)
• [(\s|\S)] --> Match een whitespace, tab etc (\s) of (|) een non-whitespace (\S)
• {4} --> en dat 4 tekens lang
Dat zou dus betekenen dat als ik mijn functie aanroep zoals in gegeven voorbeeld ik terug zou moeten krijgen: @D*it is@een test*bl@aat
Zoals je ziet verwacht ik dus alleen * gereplaced op plaatsen waar de positie een veelvoud van 4 is (later dus 320).
Wat ik echter terug krijg is het volgende: @ is@test@at
Alle sterretjes vervangen of foetsie...
Korte samenvatting
Hoe kan ik in een string alleen tekens op een bepaalde positie (veelvoud van x, dus op b.v. iedere 320-ste positie) vervangen door een ander teken? En hoe schrijf ik dat regex pattern dan?
edit:
Oh, voor de syntax van regex gebruik ik de documentatie van MS
Ik ben dus ook niet op zoek naar http://www.regxlib.com/ en andere posts omdat deze allemaal met PHP-regex werken (en deze werkt wat anders zoals ik het begrijp (correct me if I'm wrong))
Oh, voor de syntax van regex gebruik ik de documentatie van MS
Ik ben dus ook niet op zoek naar http://www.regxlib.com/ en andere posts omdat deze allemaal met PHP-regex werken (en deze werkt wat anders zoals ik het begrijp (correct me if I'm wrong))
/me Waarschuwing: Lees alsjeblieft goed de post voordat je met suggesties komt, ik probeer deze draad "zo schoon mogelijk" te houden.
...en ondertussen stoei ik even verder op zoek naar de oplossing
[ Voor 27% gewijzigd door RobIII op 26-11-2003 17:22 ]
There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.
Je eigen tweaker.me redirect
Over mij