tags:

views:

105

answers:

3

Hi. Is this possible with regex?

I have a file, and if a '@' is found in the file, the text after the '@' with the '@' is to be replaced with the file with the same name as after the '@'.

File1: "this text is found in file1"
File2: "this file will contain text from file1: @file1".
File2 after regex: "this file will contain text from file1: this text is found in file1".

I wish to do this with php and I've heard that the preg function is better than the ereg, but whatever works is fine with me =)

Thanks a lot!

EDIT:

It has to be programmed, so that it looks through file2 without knowing which files to concatenate before it has gone through all occurrences of a @ :)

+2  A: 

PHP's native functions str_pos and str_replace are better to use when you're searching through larger files or strings. ;)

Ben Fransen
str_pos won't help when there is many occurences of @ ?
Johannes
+1  A: 

Much cleaner:

<?php

$content = file_get_content('content.txt');
$m = array();
preg_match_all('`@([^\s]*)(\s|\Z)`ism', $content, $m, PREG_SET_ORDER);
foreach($m as $match){
  $innerContent = file_get_contents($match[1]);
  $content = str_replace('@'.$match[1], $innerContent, $content);
}
// done!

?>

regex tested with: http://www.spaweditor.com/scripts/regex/index.php

thephpdeveloper
thanks! but it has to be programmed, so that it looks through file2 without knowing which files to concatenate before it has gone through all occurrences of a @ :)
Johannes
well the example given and your post did not mention about multiple occurrences of @. let me update.
thephpdeveloper
well here's a better one which is much cleaner. it will detect from @ to a space character, EOL or end of text.
thephpdeveloper
+2  A: 

First of all the grammar of your templating is not a very good one becuase the parser may not exactly sure when will the file name ends. My suggestion would be that you change to the one that can better detect the boundry like {@:filename}.

Anyhow, the code I give below follows your question.

<?php

// RegEx Utility functions -------------------------------------------------------------------------

function ReplaceAll($RegEx, $Processor, $Text) {
    // Make sure the processor can be called
    if(!is_callable($Processor))
        throw new Exception("\"$Processor\" is not a callable.");

    // Do the Match
    preg_match_all($RegEx, $Text, $Matches, PREG_OFFSET_CAPTURE + PREG_SET_ORDER);

    // Do the replacment
    $NewText    = "";
    $MatchCount = count($Matches);
    $PrevOffset = 0;
    for($i = 0; $i < $MatchCount; $i++) {
        // Get each match and the full match information
        $EachMatch = $Matches[$i];
        $FullMatch = is_array($EachMatch) ? $EachMatch[0] : $EachMatch;
        // Full match is                      each match if no grouping is used in the regex
        // Full match is the first element of each match if    grouping is used in the regex.

        $MatchOffset     = $FullMatch[1];
        $MatchText       = $FullMatch[0];
        $MatchTextLength = strlen($MatchText);
        $NextOffset      = $MatchOffset + $MatchTextLength;

        // Append the non-match and the replace of the match
        $NewText .= substr($Text, $PrevOffset, $MatchOffset - $PrevOffset);
        $NewText .= $Processor($EachMatch);

        // The next prev-offset
        $PrevOffset = $NextOffset;
    }
    // Append the rest of the text
    $NewText .= substr($Text, $PrevOffset);

    return $NewText;
}

function GetGroupMatchText($Match, $Index) {
    if(!is_array($Match))
        return $Match[0];

    $Match = $Match[$Index];
    return $Match[0];
}

// Replacing by file content -----------------------------------------------------------------------

$RegEx_FileNameInText       = "/@([a-zA-Z0-9]+)/";  // Group #1 is the file name
$ReplaceFunction_ByFileName = "ReplaceByFileContent";
function ReplaceByFileContent($Match) {
    $FileName = GetGroupMatchText($Match, 1);       // Group # is the gile name

    // $FileContent = get_file_content($FileName);  // Get the content of the file
    $FileContent = "{@ content of: $FileName}";    // Dummy content for testing

    return $FileContent;    // Returns the replacement
}

// Main --------------------------------------------------------------------------------------------

$Text = " === @file1 ~ @file2 === ";
echo ReplaceAll($RegEx_FileNameInText, $ReplaceFunction_ByFileName, $Text);

This will returns === {@ content of: file1} ~ {@ content of: file2} === .

The program will replace all the regex match with the replacement returned from the result of the given function name. In this case, the callback function is ReplaceByFileContent in which the file name is extract from the group #1 in the regex.

I believe my code is self documented but if you have any question, you can ask me.

Hope I helps.

NawaMan
wow what an excellent answer, thanks!
Johannes