Page 1 of 1

regex, delimiters

Posted: Tue Jan 09, 2007 7:04 pm
by jonathant
I have a textbox that will be used to create fill-in-the-blank questions. I want the users to be able to denote the words to be blanked out by setting a delimiter like "**" or something. What is the best way to extract the delimited words and place them into an array? Also, I'd like to change the question string to substitute an underscore in place of the phrase. I'm thinking two different regular expressions will be the way to go, but I'm really weak with them so any help would be greatly appreciated. You guys and gals are great!

Code: Select all

This is an **example** fill-in-the-blank **question**?

Code: Select all

// I need the array to look like:
array ('example', 'question');

// and the question string to look like:
"This is an _ fill-in-the-blank _?"

Posted: Tue Jan 09, 2007 8:12 pm
by Ollie Saunders
How about you output a paragraph of text with <input type="text">s wherever you have a blank to fill in instead.

Posted: Tue Jan 09, 2007 8:59 pm
by Ambush Commander
Agreed.

Posted: Tue Jan 09, 2007 10:11 pm
by jonathant
ole wrote:How about you output a paragraph of text with <input type="text">s wherever you have a blank to fill in instead.
That's what I planned on doing. I just threw out the underscore as an example. What about finding the words in the first place?

Code: Select all

$string = "This is the **example** string that was taken from the **question** create form.";

preg_match('(**)', $string, $blanks);

echo "The words are: <br>";

foreach ($blanks as $word) {
     echo $word."<br>";
}
I have no idea how to get the extract the words between the **.

Posted: Tue Jan 09, 2007 11:53 pm
by feyd
"*" is a metacharacter. If you want to match the character, it must be escaped.

The solution to finding text between two given elements has been talked about quite a few times around here. Please search.

Posted: Wed Jan 10, 2007 5:16 am
by Ollie Saunders
Where is any finding required? The data comes to you in $_POST as a nice associative array.

Posted: Sun Jan 14, 2007 10:17 am
by jonathant
Maybe this isn't a regular expression problem at all. Let's say I want to turn this:
This is an {example} question. It could be {fairly long} with multiple {blanks}.
Into this (name and id tags left out for abbreviation).
This is an <input type="text" /> question. It could be <input type="text" /> with multiple <input type="text" />.
Here's what I've got so far, that isn't working.

Code: Select all

// $question = Array ( [id] => 7 [question] => An {example} question. [sequence] => 6 [type] => fb )

if ($question['type'] == 'fb') {
                // convert string
                $pos=0;
                $open_positions=array();
                while (strpos($question['question'], "{", $pos)) {
                    $open_positions[]=strpos($question['question'], "{", $pos);
                    $pos=strpos($question['question'], "{", $pos) + 1;
                }
                
                $pos=0;
                $closed_positions=array();
                while (strpos($question['question'], "}", $pos)) {
                    $closed_positions[]=strpos($question['question'], "}", $pos);
                    $pos=strpos($question['question'], "}", $pos) + 1;
                }
                
                if (count($open_positions) != count($closed_positions)) {
                    return FALSE;
                }
                
                $positions=array_merge($open_positions, $closed_positions);
                sort($positions);
                
                $counter=0;
                $wordcount=1;
                $new_question=$question['question'];
                while (count($positions) > $counter) {
                    if ($counter == 0) {
                        $length = $positions[$counter + 1] - $positions[$counter] - 2;
                    } else {
line 132                         $length = $positions[$counter + 1] - $positions[$counter] - 1;
                    }
                    $replace="<input type=\"text\" id=\"word_".$wordcount."\" name=\"word_".$wordcount."\" /></input>";
                    substr_replace($new_question, $replace ,$positions[$counter], $length);
                    $counter = $counter + 1;
                    $wordcount = $wordcount + 1;
                }
                
                $prepared_questions[]=array('id' => $question['id'], 'question' => $new_question,
                    'sequence' => $question['sequence'], 'type' => $question['type']);
            }
A PHP Error was encountered
Severity: Notice
Message: Undefined offset: 2
Filename: student/take_test.php
Line Number: 132

Posted: Sun Jan 14, 2007 10:39 am
by Ollie Saunders
That's a whole lot of code. You must want to start off with

Code: Select all

$str = preg_replace('~\b\{[^\}]+\}\b~', '<input type="text" />', $str);
and go from there.

edit: forgot to escape some stuff

Posted: Sun Jan 14, 2007 10:44 am
by feyd
The following may work better in the end.

Code: Select all

<?php

$str = 'This is an {example} question. It could be {fairly long} with multiple {blanks}.';

function fixName($a)
{
	return '<input type="text" name="' . preg_replace('#[^a-z0-9]#i', '_', $a[1]) . '" />';
}

$newstr = preg_replace_callback('#\{([a-z0-9 -]+)\}#i', 'fixName', $str);
echo $str, PHP_EOL, $newstr;

?>

Code: Select all

This is an {example} question. It could be {fairly long} with multiple {blanks}.
This is an <input type="text" name="example" /> question. It could be <input type="text" name="fairly_long" /> with multiple <input type="text" name="blanks" />.

Posted: Sun Jan 14, 2007 3:10 pm
by jonathant
Thanks for the help! I ended up using feyd's solution which was only slightly less code than my own :)

Posted: Sun Jan 14, 2007 4:39 pm
by Ollie Saunders
Yeah feyd's was more complete than mine.
Which is unusual; feyd is usually a man of few words or, in this case, variables.

Posted: Sun Jan 14, 2007 4:41 pm
by feyd
ole wrote:Which is unusual; feyd is usually a man of few words or, in this case, variables.
:D