From c2ba17858c1994d9654a5ca64cb9fb22780654c1 Mon Sep 17 00:00:00 2001 From: ppichet Date: Wed, 16 Jan 2013 22:04:29 -0500 Subject: [PATCH] MDL-33105 flexible apply_units() function Allow use of thousands separator as long as the decimal separator is used in the number. --- question/type/numerical/question.php | 11 +--- question/type/numerical/questiontype.php | 52 +++++++++++++------ .../numerical/tests/answerprocessor_test.php | 19 +++++++ 3 files changed, 55 insertions(+), 27 deletions(-) diff --git a/question/type/numerical/question.php b/question/type/numerical/question.php index 0e48155c6de..2e39db1c567 100644 --- a/question/type/numerical/question.php +++ b/question/type/numerical/question.php @@ -106,10 +106,6 @@ class qtype_numerical_question extends question_graded_automatically { return false; } - if ($this->ap->contains_thousands_seaparator($response['answer'])) { - return false; - } - return true; } @@ -131,11 +127,6 @@ class qtype_numerical_question extends question_graded_automatically { return get_string('unitnotselected', 'qtype_numerical'); } - if ($this->ap->contains_thousands_seaparator($response['answer'])) { - return get_string('pleaseenteranswerwithoutthousandssep', 'qtype_numerical', - $this->ap->get_separator()); - } - return ''; } @@ -287,7 +278,7 @@ class qtype_numerical_question extends question_graded_automatically { list($value, $unit, $multiplier) = $this->ap->apply_units( $currentanswer, $selectedunit); $answer = $this->get_matching_answer($value, $multiplier); - $answerid = reset($args); // itemid is answer id. + $answerid = reset($args); // Itemid is answer id. return $options->feedback && $answer && $answerid == $answer->id; } else if ($component == 'question' && $filearea == 'hint') { diff --git a/question/type/numerical/questiontype.php b/question/type/numerical/questiontype.php index c02e91f6a72..ba0d64dc030 100644 --- a/question/type/numerical/questiontype.php +++ b/question/type/numerical/questiontype.php @@ -75,8 +75,8 @@ class qtype_numerical extends question_type { array('questionid' => $question->id), 'id ASC'); $this->get_numerical_units($question); - // get_numerical_options() need to know if there are units - // to set correctly default values + // Function get_numerical_options() need to know if there are units + // to set correctly default values. $this->get_numerical_options($question); // If units are defined we strip off the default unit from the answer, if @@ -153,7 +153,7 @@ class qtype_numerical extends question_type { global $DB; $context = $question->context; - // Get old versions of the objects + // Get old versions of the objects. $oldanswers = $DB->get_records('question_answers', array('question' => $question->id), 'id ASC'); $oldoptions = $DB->get_records('question_numerical', @@ -167,7 +167,7 @@ class qtype_numerical extends question_type { $units = $result->units; } - // Insert all the new answers + // Insert all the new answers. foreach ($question->answer as $key => $answerdata) { // Check for, and ingore, completely blank answer from the form. if (trim($answerdata) == '' && $question->fraction[$key] == 0 && @@ -200,7 +200,7 @@ class qtype_numerical extends question_type { $answer->feedbackformat = $question->feedback[$key]['format']; $DB->update_record('question_answers', $answer); - // Set up the options object + // Set up the options object. if (!$options = array_shift($oldoptions)) { $options = new stdClass(); } @@ -323,7 +323,7 @@ class qtype_numerical extends question_type { $units = array(); $unitalreadyinsert = array(); foreach ($question->multiplier as $i => $multiplier) { - // Discard any unit which doesn't specify the unit or the multiplier + // Discard any unit which doesn't specify the unit or the multiplier. if (!empty($question->multiplier[$i]) && !empty($question->unit[$i]) && !array_key_exists($question->unit[$i], $unitalreadyinsert)) { $unitalreadyinsert[$question->unit[$i]] = 1; @@ -632,17 +632,35 @@ class qtype_numerical_answer_processor { // Strip spaces (which may be thousands separators) and change other forms // of writing e to e. $response = str_replace(' ', '', $response); + // Strip thousand separators like half space. + if (!in_array($this->thousandssep, array(',', '.', ' '))) { + if (strpos($value, $this->thousandssep) !== false) { + $response = str_replace($this->thousandssep, '', $response); + } + } $response = preg_replace('~(?:e|E|(?:x|\*|×)10(?:\^|\*\*))([+-]?\d+)~', 'e$1', $response); - - // If a . is present or there are multiple , (i.e. 2,456,789 ) assume , - // is a thouseands separator, and strip it, else assume it is a decimal - // separator, and change it to .. - if (strpos($response, '.') !== false || substr_count($response, ',') > 1) { - $response = str_replace(',', '', $response); - } else { - $response = str_replace(',', '.', $response); + // Dot . is mostly a decimal separator there a few exceptions where it is a thousand separator + // If a . is present or there are multiple , (i.e. 2,456,789 ) assume, + // is a thousands separator and strip it or else assume it is a decimal + // separator and change it to . + // if only one and it is , then change to . + if (substr_count($response, ',')+ substr_count($response, '.') == 1 ) { + if (strpos($response, ',') !== false) { + $response = str_replace(',', '.', $response); + } + } else if (substr_count($response, ',') == 1 && substr_count($response, '.') == 1) { + if (strpos($response, '.') > strpos($response, ',')) { // Then , is thousand. + $response = str_replace(',', '', $response); + } else { + $response = str_replace('.', '', $response); + $response = str_replace(',', '.', $response); + } + } else if (substr_count($response, ',') > 1) { + $response = str_replace(',', '', $response); + } else if (substr_count($response, '.') > 1) { + $response = str_replace('.', '', $response); + $response = str_replace(',', '.', $response); } - $regex = '[+-]?(?:\d+(?:\\.\d*)?|\\.\d+)(?:e[-+]?\d+)?'; if ($this->unitsbefore) { $regex = "/$regex$/"; @@ -655,7 +673,7 @@ class qtype_numerical_answer_processor { $numberstring = $matches[0]; if ($this->unitsbefore) { - // substr returns false when it means '', so cast back to string. + // Function substr returns false when it means '', so cast back to string. $unit = (string) substr($response, 0, -strlen($numberstring)); } else { $unit = (string) substr($response, strlen($numberstring)); @@ -671,7 +689,7 @@ class qtype_numerical_answer_processor { $multiplier = null; } - return array($numberstring + 0, $unit, $multiplier); // + 0 to convert to number. + return array($numberstring + 0, $unit, $multiplier); // Add + 0 to convert to number. } /** diff --git a/question/type/numerical/tests/answerprocessor_test.php b/question/type/numerical/tests/answerprocessor_test.php index f27bb2ff890..7a81f668d44 100644 --- a/question/type/numerical/tests/answerprocessor_test.php +++ b/question/type/numerical/tests/answerprocessor_test.php @@ -131,9 +131,28 @@ class qtype_numerical_answer_processor_test extends advanced_testcase { $ap = new qtype_numerical_answer_processor(array(), false, ',', ' '); $this->assertEquals(array(-1000, '', null), $ap->apply_units('-1 000')); + $this->assertEquals(array(-1000000, '', null), $ap->apply_units('-1 000 000')); + $this->assertEquals(array(-1000000, '', null), $ap->apply_units('-1.000.000')); + $this->assertEquals(array(-1000000, '', null), $ap->apply_units('-1,000,000')); + $this->assertEquals(array(-1000.1, '', null), $ap->apply_units('-1000,1')); + $this->assertEquals(array(-1000.1, '', null), $ap->apply_units('-1.000,1')); + $this->assertEquals(array(-1000.1, '', null), $ap->apply_units('-1,000.1')); $this->assertEquals(array(3.14159, '', null), $ap->apply_units('3,14159')); } + public function test_deutsch_style() { + $ap = new qtype_numerical_answer_processor(array(), false, ',', '.'); + + $this->assertEquals(array(-1000, '', null), $ap->apply_units('-1 000')); + $this->assertEquals(array(-1000000, '', null), $ap->apply_units('-1 000 000')); + $this->assertEquals(array(-1000000, '', null), $ap->apply_units('-1.000.000')); + $this->assertEquals(array(-1000000, '', null), $ap->apply_units('-1.000.000,')); + $this->assertEquals(array(-1000.1, '', null), $ap->apply_units('-1000,1')); + $this->assertEquals(array(-1000.1, '', null), $ap->apply_units('-1.000,1')); + $this->assertEquals(array(-1000.1, '', null), $ap->apply_units('-1,000.1')); + $this->assertEquals(array(3.14159, '', null), $ap->apply_units('3.14159')); + $this->assertEquals(array(3.14159, '', null), $ap->apply_units('3,14159')); + } public function test_percent() { $ap = new qtype_numerical_answer_processor(array('%' => 100), false, '.', ','); -- 2.43.0