crazytonyi Posted October 16, 2008 Share Posted October 16, 2008 I've written a script that converts a source of data into XML. Now it follows a pretty standard pattern but does it is not consistent (that sounded weird...) Here's an example: <schedule> <employee name="Joe Smith"> <day date="10/13/2008"> <shift><descr>Sweeping</descr><starttime>7:45 AM</starttime><endtime>12:15 PM</endtime></shift> <shift><descr>Yodeling</descr><starttime>1:15 PM</starttime><endtime>6:00 PM</endtime></shift> </day> <day date="10/14/2008"> <shift><descr>Mopping</descr><starttime>7:45 AM</starttime><endtime>11:15 AM</endtime></shift> </day> </employee> <consultant name="Butternut McClintock"> <day date="10/13/2008"> <shift><descr>Cliff Diving</descr><starttime>7:45 AM</starttime><endtime>12:15 PM</endtime></shift> </day> <day date="10/14/2008"> <shift><descr>Chewing Food</descr><starttime>7:45 AM</starttime><endtime>11:15 AM</endtime></shift> <shift><descr>Crackin' Wise</descr><starttime>1:15 PM</starttime><endtime>6:00 PM</endtime></shift> </day> </employee> </schedule> The problem is that I want to move the date in front of the appropriate times (start and end times) so that I can ditch the day tag and just have a list of shifts per employee. But I don't want to create arrays (yet) and I can't use regex (I don't think) because the number of shifts changes per day, so it's not regular enough. Is there a way, preferably without using loops, to just say "find this regular expression, and while you're at it, find this OTHER regular expression that comes after it, and then stop looking when you get to this end point" ? I thought maybe I could use a * or + to imply that the entire section repeats, but that got really confusing and kept throwing errors. Help! Please! Thanks Quote Link to comment https://forums.phpfreaks.com/topic/128675-recursive-string-replace/ Share on other sites More sharing options...
Orio Posted October 16, 2008 Share Posted October 16, 2008 I don't really get what replacement you are looking for. Can you give a small example of the input and the expected output you want? Orio. Quote Link to comment https://forums.phpfreaks.com/topic/128675-recursive-string-replace/#findComment-666902 Share on other sites More sharing options...
crazytonyi Posted October 16, 2008 Author Share Posted October 16, 2008 Thanks for replying. Sorry, this is all VERY new for me. I've got a ton more problems, but this one may lead me to a generally better understanding. Okay, so the input is: <schedule> <employee name="Joe Smith"> <day date="10/13/2008"> <shift><descr>Sweeping</descr><starttime>7:45 AM</starttime><endtime>12:15 PM</endtime></shift> <shift><descr>Yodeling</descr><starttime>1:15 PM</starttime><endtime>6:00 PM</endtime></shift> </day> <day date="10/14/2008"> <shift><descr>Mopping</descr><starttime>7:45 AM</starttime><endtime>11:15 AM</endtime></shift> </day> </employee> <consultant name="Butternut McClintock"> <day date="10/13/2008"> <shift><descr>Cliff Diving</descr><starttime>7:45 AM</starttime><endtime>12:15 PM</endtime></shift> </day> <day date="10/14/2008"> <shift><descr>Chewing Food</descr><starttime>7:45 AM</starttime><endtime>11:15 AM</endtime></shift> <shift><descr>Crackin' Wise</descr><starttime>1:15 PM</starttime><endtime>6:00 PM</endtime></shift> </day> </employee> </schedule> The output (or a sampling of it) would be: <schedule> <employee name="Joe Smith"> <shift><descr>Sweeping</descr><starttime>10/13/2008 7:45 AM</starttime><endtime>10/13/2008 12:15 PM</endtime></shift> <shift><descr>Yodeling</descr><starttime>10/13/2008 1:15 PM</starttime><endtime>10/13/2008 6:00 PM</endtime></shift> <shift><descr>Mopping</descr><starttime>10/14/2008 7:45 AM</starttime><endtime>10/14/2008 11:15 AM</endtime></shift> </employee> </schedule> Quote Link to comment https://forums.phpfreaks.com/topic/128675-recursive-string-replace/#findComment-666928 Share on other sites More sharing options...
Orio Posted October 16, 2008 Share Posted October 16, 2008 I am sure that there are better ways doing that, but here's what I've come up with: <?php $data = <<<DATA <schedule> <employee name="Joe Smith"> <day date="10/13/2008"> <shift><descr>Sweeping</descr><starttime>7:45 AM</starttime><endtime>12:15 PM</endtime></shift> <shift><descr>Yodeling</descr><starttime>1:15 PM</starttime><endtime>6:00 PM</endtime></shift> </day> <day date="10/14/2008"> <shift><descr>Mopping</descr><starttime>7:45 AM</starttime><endtime>11:15 AM</endtime></shift> </day> </employee> <consultant name="Butternut McClintock"> <day date="10/13/2008"> <shift><descr>Cliff Diving</descr><starttime>7:45 AM</starttime><endtime>12:15 PM</endtime></shift> </day> <day date="10/14/2008"> <shift><descr>Chewing Food</descr><starttime>7:45 AM</starttime><endtime>11:15 AM</endtime></shift> <shift><descr>Crackin' Wise</descr><starttime>1:15 PM</starttime><endtime>6:00 PM</endtime></shift> </day> </employee> </schedule> DATA; $regex = '#<day date="([^"]+)">(.*?)<starttime>([^>]+)</starttime><endtime>([^>]+)</endtime>.*?</day>#ise'; $replacement = "trim('$2').'<starttime>$1 $3</starttime><endtime>$1 $4</endtime>'"; $data = preg_replace($regex, $replacement, $data); ?> Orio. Quote Link to comment https://forums.phpfreaks.com/topic/128675-recursive-string-replace/#findComment-666935 Share on other sites More sharing options...
crazytonyi Posted October 16, 2008 Author Share Posted October 16, 2008 That would work for the first shift, but what about any others that follow? I could do another find/replace for the ones below using the first one (maybe?) but I'm not even sure that's an option. My original idea was to grab all of the "day" groups and then just make the date a variable that gets added to a regex, BUT I don't know how to get that array back into the string. Quote Link to comment https://forums.phpfreaks.com/topic/128675-recursive-string-replace/#findComment-666956 Share on other sites More sharing options...
Orio Posted October 16, 2008 Share Posted October 16, 2008 From what I've tested, this works. I don't understand- what's the problem? Orio. Quote Link to comment https://forums.phpfreaks.com/topic/128675-recursive-string-replace/#findComment-666975 Share on other sites More sharing options...
nrg_alpha Posted October 16, 2008 Share Posted October 16, 2008 From what I've tested, this works. I don't understand- what's the problem? Orio. Not to take sides.. but there does seem to be an issue, Orio... When I use your code, this is the output (when right-clicking and viewing source): <schedule> <employee name="Joe Smith"> <shift><descr>Sweeping</descr><starttime>10/13/2008 7:45 AM</starttime><endtime>10/13/2008 12:15 PM</endtime> <shift><descr>Mopping</descr><starttime>10/14/2008 7:45 AM</starttime><endtime>10/14/2008 11:15 AM</endtime> </employee> <consultant name="Butternut McClintock"> <shift><descr>Cliff Diving</descr><starttime>10/13/2008 7:45 AM</starttime><endtime>10/13/2008 12:15 PM</endtime> <shift><descr>Chewing Food</descr><starttime>10/14/2008 7:45 AM</starttime><endtime>10/14/2008 11:15 AM</endtime> </employee> </schedule> Notice that the pattern only effects the first <shift> lines in each section. I made a slight modification to your regex and replacement, and I think this will grab every line into consideration: $regex = '#<day date="([^"]+)">(.*?)<starttime>([^>]+)</starttime><endtime>([^>]+)</endtime>(.*?)</day>#ise'; $replacement = "trim('$2').'<starttime>$1 $3</starttime><endtime>$1 $4</endtime>$5'"; What I did here was make a capture out of the last .*? between </endtime> and </day> (as you'll notice the lack of outputted closing </shift> tags in the initial solution). Then simply added $5 after </endtime> in $replacement. Output: <schedule> <employee name="Joe Smith"> <shift><descr>Sweeping</descr><starttime>10/13/2008 7:45 AM</starttime><endtime>10/13/2008 12:15 PM</endtime></shift> <shift><descr>Yodeling</descr><starttime>1:15 PM</starttime><endtime>6:00 PM</endtime></shift> <shift><descr>Mopping</descr><starttime>10/14/2008 7:45 AM</starttime><endtime>10/14/2008 11:15 AM</endtime></shift> </employee> <consultant name="Butternut McClintock"> <shift><descr>Cliff Diving</descr><starttime>10/13/2008 7:45 AM</starttime><endtime>10/13/2008 12:15 PM</endtime></shift> <shift><descr>Chewing Food</descr><starttime>10/14/2008 7:45 AM</starttime><endtime>10/14/2008 11:15 AM</endtime></shift> <shift><descr>Crackin Wise</descr><starttime>1:15 PM</starttime><endtime>6:00 PM</endtime></shift> </employee> </schedule> Cheers, NRG EDIT: Oops.. seems to not quite work with a few lines: Example: <shift><descr>Crackin Wise</descr><starttime>1:15 PM</starttime><endtime>6:00 PM</endtime></shift> Quote Link to comment https://forums.phpfreaks.com/topic/128675-recursive-string-replace/#findComment-667152 Share on other sites More sharing options...
effigy Posted October 16, 2008 Share Posted October 16, 2008 Is Perl an option? I would array this, if not as an end result, at least in the manner of XML->array->parse->XML. Quote Link to comment https://forums.phpfreaks.com/topic/128675-recursive-string-replace/#findComment-667183 Share on other sites More sharing options...
crazytonyi Posted October 17, 2008 Author Share Posted October 17, 2008 Thanks for all the great feedback! It got my gears turning. I regret to admit that I had to use a for loop after all. Here's what I came up with: /* Gets the pattern for the main date and top shift */ $findshift = '/<day date=\"(.*)\">\n<shift>(<descr>.*<\/descr>)<starttime>(.*)<\/starttime><endtime>(.*)<\/endtime>/'; /* The replacement code...notice how the day tag is gone */ $fixshift ="<shift>$2<startime>$1 $3</startime><endtime>$1 $4</endtime>"; /*moves the date down to the first shift of that date */ $text = preg_replace($findshift, $fixshift, $text); /* looks for the top shift and the one below it */ $findshift2 = '/(\n<shift>.*time>(\d*\/\d*\/\d*).*<\/shift>\n)(<shift>(<descr>.*<\/descr>)<starttime>(\d{1,2}:\d{2} (AM|PM))<\/starttime><endtime>(.*)<\/endtime>)/'; /*returns the first shift and shift below, now both with dates */ $fixshift2 ="$1<shift>$4<startime>$2 $5</startime><endtime>$2 $6</endtime>"; /* tried regular preg_replace, but only worked on groups of two shifts per day. Tried doing it twice, and only got three dates inserted. Figured the likely hood of anyone doing more than 8 shifts in a day, so I have a loop that does it 8 times (the current record for this weeks data was 5 shifts, so better safe than sorry) */ for ($i = 1; $i <= 8; $i++) { $text = preg_replace($findshift2, $fixshift2, $text); } /* finally, delete all day close tags */ $text=str_replace("</day>\n", "", $text); If anyone knows a more slick way of doing this, feel free to school me. A Quote Link to comment https://forums.phpfreaks.com/topic/128675-recursive-string-replace/#findComment-667664 Share on other sites More sharing options...
sasa Posted October 17, 2008 Share Posted October 17, 2008 try <?php $test = '<schedule> <employee name="Joe Smith"> <day date="10/13/2008"> <shift><descr>Sweeping</descr><starttime>7:45 AM</starttime><endtime>12:15 PM</endtime></shift> <shift><descr>Yodeling</descr><starttime>1:15 PM</starttime><endtime>6:00 PM</endtime></shift> </day> <day date="10/14/2008"> <shift><descr>Mopping</descr><starttime>7:45 AM</starttime><endtime>11:15 AM</endtime></shift> </day> </employee> <consultant name="Butternut McClintock"> <day date="10/13/2008"> <shift><descr>Cliff Diving</descr><starttime>7:45 AM</starttime><endtime>12:15 PM</endtime></shift> </day> <day date="10/14/2008"> <shift><descr>Chewing Food</descr><starttime>7:45 AM</starttime><endtime>11:15 AM</endtime></shift> <shift><descr>Crackin\' Wise</descr><starttime>1:15 PM</starttime><endtime>6:00 PM</endtime></shift> </day> </employee> </schedule>'; $patern = '|(\s*<day date="(.*?)">)(\s*<shift>.*?<starttime>)(.*?)(</starttime><endtime>)(.*?)(</endtime></shift>)|is'; $r = '$3$2 $4$5$2 $6$7 $1'; while (strpos($test, '<day')){ $test = preg_replace($patern, $r, $test); $test = preg_replace('|\s+<day[^>]*>\s+</day>|is', '', $test); } echo $test; ?> Quote Link to comment https://forums.phpfreaks.com/topic/128675-recursive-string-replace/#findComment-667711 Share on other sites More sharing options...
ghostdog74 Posted October 17, 2008 Share Posted October 17, 2008 Thanks for replying. Sorry, this is all VERY new for me. I've got a ton more problems, but this one may lead me to a generally better understanding. Okay, so the input is: <schedule> <employee name="Joe Smith"> <day date="10/13/2008"> <shift><descr>Sweeping</descr><starttime>7:45 AM</starttime><endtime>12:15 PM</endtime></shift> <shift><descr>Yodeling</descr><starttime>1:15 PM</starttime><endtime>6:00 PM</endtime></shift> </day> <day date="10/14/2008"> <shift><descr>Mopping</descr><starttime>7:45 AM</starttime><endtime>11:15 AM</endtime></shift> </day> </employee> <consultant name="Butternut McClintock"> <day date="10/13/2008"> <shift><descr>Cliff Diving</descr><starttime>7:45 AM</starttime><endtime>12:15 PM</endtime></shift> </day> <day date="10/14/2008"> <shift><descr>Chewing Food</descr><starttime>7:45 AM</starttime><endtime>11:15 AM</endtime></shift> <shift><descr>Crackin' Wise</descr><starttime>1:15 PM</starttime><endtime>6:00 PM</endtime></shift> </day> </employee> </schedule> The output (or a sampling of it) would be: <schedule> <employee name="Joe Smith"> <shift><descr>Sweeping</descr><starttime>10/13/2008 7:45 AM</starttime><endtime>10/13/2008 12:15 PM</endtime></shift> <shift><descr>Yodeling</descr><starttime>10/13/2008 1:15 PM</starttime><endtime>10/13/2008 6:00 PM</endtime></shift> <shift><descr>Mopping</descr><starttime>10/14/2008 7:45 AM</starttime><endtime>10/14/2008 11:15 AM</endtime></shift> </employee> </schedule> from the way i see what you want to get, there's no need for regular expression. Just iterate the file, skip lines that contains day tags $xmlfile = "file"; $fh=fopen($xmlfile,"r"); while( ( $line = fgets( $fh,4096) ) !==FALSE ){ if( strpos($line,'<day')==FALSE && strpos($line,'</day>') == FALSE){ echo $line; } } fclose($fh); Quote Link to comment https://forums.phpfreaks.com/topic/128675-recursive-string-replace/#findComment-668006 Share on other sites More sharing options...
nrg_alpha Posted October 17, 2008 Share Posted October 17, 2008 from the way i see what you want to get, there's no need for regular expression. Just iterate the file, skip lines that contains day tags $xmlfile = "file"; $fh=fopen($xmlfile,"r"); while( ( $line = fgets( $fh,4096) ) !==FALSE ){ if( strpos($line,'<day')==FALSE && strpos($line,'</day>') == FALSE){ echo $line; } } fclose($fh); But where in your code does it extract the date found in the day tag and insert that info after the <starttime> and <endtime> tags? Quote Link to comment https://forums.phpfreaks.com/topic/128675-recursive-string-replace/#findComment-668015 Share on other sites More sharing options...
ghostdog74 Posted October 17, 2008 Share Posted October 17, 2008 $xmlfile = "file"; $fh=fopen($xmlfile,"r"); while( ( $line = fgets( $fh,4096) ) !==FALSE ){ if( strpos($line,'<day')!==FALSE ){ $day = split('"',$line); $date = $day[1]; continue; } if ( strpos($line,"<shift>")!==FALSE){ $sh = split("<endtime>",$line); $sh[1]=$date . $sh[1]; echo join("<endtime>",$sh); }elseif( strpos($line,"</day>") !==FALSE) { continue; }else{ echo $line; } } fclose($fh); Quote Link to comment https://forums.phpfreaks.com/topic/128675-recursive-string-replace/#findComment-668035 Share on other sites More sharing options...
nrg_alpha Posted October 17, 2008 Share Posted October 17, 2008 Ah, so it isn't as simple as skipping lines with day tags afterall (that was the point of my last post). Quote Link to comment https://forums.phpfreaks.com/topic/128675-recursive-string-replace/#findComment-668055 Share on other sites More sharing options...
ghostdog74 Posted October 17, 2008 Share Posted October 17, 2008 Ah, so it isn't as simple as skipping lines with day tags afterall (that was the point of my last post). yes, i overlooked what he wants, my bad . Anyway, the difference is that even if i don't explain my code, OP should be able to understand what it's doing. Quote Link to comment https://forums.phpfreaks.com/topic/128675-recursive-string-replace/#findComment-668404 Share on other sites More sharing options...
ddrudik Posted October 29, 2008 Share Posted October 29, 2008 I didn't read through all of the thread, but here's what it seems you want from your before and after example: <pre> <?php $xml=<<<EOL <schedule> <employee name="Joe Smith"> <day date="10/13/2008"> <shift><descr>Sweeping</descr><starttime>7:45 AM</starttime><endtime>12:15 PM</endtime></shift> <shift><descr>Yodeling</descr><starttime>1:15 PM</starttime><endtime>6:00 PM</endtime></shift> </day> <day date="10/14/2008"> <shift><descr>Mopping</descr><starttime>7:45 AM</starttime><endtime>11:15 AM</endtime></shift> </day> </employee> <consultant name="Butternut McClintock"> <day date="10/13/2008"> <shift><descr>Cliff Diving</descr><starttime>7:45 AM</starttime><endtime>12:15 PM</endtime></shift> </day> <day date="10/14/2008"> <shift><descr>Chewing Food</descr><starttime>7:45 AM</starttime><endtime>11:15 AM</endtime></shift> <shift><descr>Crackin' Wise</descr><starttime>1:15 PM</starttime><endtime>6:00 PM</endtime></shift> </day> </employee> </schedule> EOL; echo '<hr>before:<br>'.htmlentities($xml); $xml=preg_replace_callback('~\s*<day date="([^"]*)">(.*?)\r\n *</day>~s','replfunc',$xml); function replfunc($match){ return preg_replace('/(?<=<starttime>|<endtime>)/',$match[1].' ',$match[2]); } echo '<hr>after:<br>'.htmlentities($xml); ?> Quote Link to comment https://forums.phpfreaks.com/topic/128675-recursive-string-replace/#findComment-677140 Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.