2012-04-14 3 views
-1

У меня трудное время со следующим:Многострочное регулярное выражение заменяет, если более двух

Существует текстовый файл с вопросами и ответами, которые мне нужно импортировать в moodle (онлайн-сайт вопроса) в определенном формате. Все черное принимает за правильные ответы, они зеленые. Формат запуска заключается в следующем:

1. Question example 

a. Wrong 

b. Wrong 

C. Wrong 

D. Right 

выход должен стать

:Question example 

:Question example 

{ 

~ Wrong 

~ Wrong 

~ Wrong 

= Right 

} 

открыть файл в слове заменить все знаки красного абзаца (я не могу сделать замену с группами) с *. После этого я экспортирую файл .docx в текст. Откройте на моем компьютере Linux и нанесите на него следующее регулярное выражение.

sed -i -e 's/^\r/\n/g' tmp #OS X white line replacement      
sed -i -e 's/\r//g' tmp #remove white lines       
sed -i -e 's:^[a-z]\.:~:' tmp #Replace Leading question letters with tilde                        
sed -i -e 's/\(^[0-9]*\.\ \)\(.*\)/}\n::\2\n::\2\n{/' tmp #regenerate tittle      
sed -i -n '${p;q};N;/\n\*/{s/"\?\n//p;b};P;D' tmp #next line starts with * append to front of current                
sed -i -e 's:^~\(.*\)\(\*.*\)$:=\1:' tmp #move * from back to = to front 
sed -i -e 's:^\*:=:' tmp #replace any remaining * with =   
sed '/^$/d' tmp #delete any remaining white lines 

Это не большой, но работает хорошо, вопросы ручной работы и много ошибок, поэтому я до сих пор ходить корыта это вручную. Трудная часть - это когда у меня есть несколько правильных ответов. Выход должен выглядеть следующим образом:

:Question example 

:Question example 

{ 

~%-100% Wrong 

~%-100% Wrong 

~%50% Right 

~%50% Right 

} 

В идеале у меня есть или PERL патч в регулярное выражение, которое подсчитывает количество = поёт между {и заменяет их с ~% 50%. И все ~ поет с% -100%. Я могу иметь этот код также для 3 правильных ответов, где каждый правильный ответ становится ~% 33%.

Является ли это выполнимым? У меня более 1000 вопросов, и это поможет автоматизировать это. Многострочная замена с sed является довольно сложной с двумя линиями, поэтому я думаю, что четыре или более строк потребует perl? У меня нет опыта в Perl.

Может ли кто-нибудь помочь мне с этим? Пожалуйста, извините мой плохой английский. Я не носитель языка.

+0

Посмотрите на седло операции космического пространства; это кажется сложным, но я думаю, что это возможно. –

+0

Что вы делаете о новых символах между Windows и Linux? Также, что касается всех персонажей, которые Word «исправляет» для вас, например, цитаты? – stark

+0

Это очень помогло бы, если бы вы показали некоторые реальные примеры. Трудно сказать из вашего примера, какой текст является реальным и который является заполнителем. Появляются ли «неправильные» и «правильные» в исходном файле? Если да, то как сказать, какие ответы правильные и что неправильно? Если нет, какова их точка в выходном файле? – Borodin

ответ

1
my $file = do { local $/; <> }; 
my @questions = split /(?<=.)(?=[0-9]+\.)/s, $file; 
for (@questions) { 
    my @lines = split /^/m; 

    my $title = shift(@lines); 
    $title =~ s/^\S+\s*/:/; 

    my $num_right; 
    my $num_wrong; 
    for (@lines) { 
     if (/Right/) { ++$num_right; } 
     elsif (/Wrong/) { ++$num_wrong; } 
    } 

    my $num_answers = $num_right + $num_wrong; 

    my $right_pct = sprintf('%.0f', $num_right/$num_answers*100); 
    my $right_prefix = $num_right == 1 ? "=" : "~%$right_pct%"; 
    my $wrong_prefix = $num_right == 1 ? "~" : "~%-100%"; 

    for (@lines) { 
     if (/Right/) { s/^\S+/$right_prefix/; } 
     elsif (/Wrong/) { s/^\S+/$wrong_prefix/; } 
    } 

    print(
     $title, 
     "\n", 
     $title, 
     "\n{\n", 
     @lines, 
     "\n}\n", 
    ); 
} 

Заменить /Right/ и /Wrong/ с чем-то соответствующее.

+0

После редактирования вы ввели отсутствующую ',' после первой новой строки в 'print'. А условный оператор должен использовать '$ num_right' вместо' $ num_wrong' при определении префиксов. – Borodin

+0

Исправлено, спасибо .. – ikegami

1

Программа ниже работает в соответствии с моим лучшим предположением о том, что вам нужно. Он работает, читая всю информацию в массив, а затем форматируя ее.

Как указано, данные включены в источник и считываются с дескриптора файла DATA. Изменение цикла на while (<>) { ... } позволит вам указать файл данных в командной строке.

Вы должны исправить меня, если мои догадки ошибаются.

use strict; 
use warnings; 

my @questions; 

while (<DATA>) { 
    next unless /\S/; 
    s/\s+$//; 
    if (/^\d+\.\s*(.+)/) { 
    push @questions, [$1]; 
    } 
    elsif (/^[A-Za-z]\.\s*(.+)/i) { 
    push @{$questions[-1]}, $1; 
    } 
} 

for my $question (@questions) { 

    my ($text, @answers) = @$question; 

    print "::$text\n" for 1, 2; 

    my $correct = grep /right/i, @answers; 
    my $percent = int(100/$correct); 

    print "{\n"; 

    if ($correct == 1) { 
    printf "%s %s\n", /right/i ? '=' : '~', $_ for @answers; 
    } 
    else { 
    my $percent = int(100/$correct); 
    printf "~%%%d%%~ %s\n", /right/i ? $percent : -100, $_ for @answers; 
    } 

    print "}\n"; 
} 

__DATA__ 
1. Question one 

a. Wrong 

b. Wrong 

c. Right 

d. Wrong 

2. Question two 

a. Right 

b. Wrong 

c. Right 

d. Wrong 

3. Question three 

a. Right 

b. Right 

c. Wrong 

d. Right 

выход

::Question one 
::Question one 
{ 
~ Wrong 
~ Wrong 
= Right 
~ Wrong 
} 
::Question two 
::Question two 
{ 
~%50%~ Right 
~%-100%~ Wrong 
~%50%~ Right 
~%-100%~ Wrong 
} 
::Question three 
::Question three 
{ 
~%33%~ Right 
~%33%~ Right 
~%-100%~ Wrong 
~%33%~ Right 
} 
1

Это может работать для вас:

cat <<\! >file.sed 
> # On encountering a digit in the first character position 
> /^[0-9]/{ 
> # Create a label to cater for last line processing 
> :end 
> # Swap to hold space 
> x 
> # Check hold space for contents. 
> # If none delete it and begin a new cycle 
> # This is to cater for the first question line 
> /./!d 
> # Remove any carriage returns 
> s/\r//g 
> # Remove any blank lines 
> s/\n\n*/\n/g 
> # Double the question line, replacing the question number by a ':' 
> # Also append a { followed by a newline 
> s/^[0-9]*\.\([^\n]*\n\)/:\1:\1{\n/ 
> # Coalesce lines beginning with a * and remove optional preceeding " 
> s/"\?\n\*/*/g 
> # Replace the wrong answers a,b,c... with ~%-100% 
> s/\n[a-zA-z]*\. \(Wrong\)/\n~%-100% \1/g 
> # Replace the right answers a,B,c... with ~%100% 
> s/\n[a-zA-Z]*\. \(Right\)/\n~%100% \1/g 
> # Assuming no more than 4 answers: 
> # Replace 4 correct answers prefix with ~%25% 
> s/\(~%100%\)\(.*\)\1\(.*\)\1\(.*\)\1/~%25%\2~%25%\3~%25%\4~%25%/ 
> # Replace 3 correct answers prefix with ~%33% 
> s/\(~%100%\)\(.*\)\1\(.*\)\1/~%33%\2~%33%\3~%33%/ 
> # Replace 2 correct answers prefix with ~%50% 
> s/\(~%100%\)\(.*\)\1/~%50%\2~%50%/ 
> # Append a newline and a } 
> s/$/\n}/ 
> # Break and so print newly formatted string 
> b 
> } 
> # Append pattern space to hold space 
> H 
> # On last line jump to end label 
> $b end 
> # Delete all lines from pattern space 
> d 
> ! 

Затем запустите:

sed -f file.sed file 
0

Ваши примеры не совпадают с этим документом ation: http://docs.moodle.org/22/en/GIFT.Вопросы названия и questiosn ограничены двумя двоеточиями не один двоеточие:

//Comment line 
::Question title 
:: Question { 
=A correct answer 
~Wrong answer1 
#A response to wrong answer1 
~Wrong answer2 
#A response to wrong answer2 
~Wrong answer3 
#A response to wrong answer3 
~Wrong answer4 
#A response to wrong answer4 
} 

Некоторые люди наивно дал вам ответы на основе ваших примеров вместо того чтобы найти реальную спецификацию, упс.

Ваш вопрос не может ответить, потому что ваш формат не показывает, какие правильные ответы. То есть:

1. Question 

a. Is this right? 

b. Or this? 

c. Or this? 

Вы говорите, что они идентифицированы с использованием цвета в исходном документе Word, и что вы делаете некоторые замены на том, что для сохранения информации; однако, вы не показываете пример этого! Oops ...

Смежные вопросы