2012-05-04 3 views
12

До того, как несколько минут назад я считал, что Perl - $ соответствует любому типу конца строки. К несчастью, мое предположение оказывается неправильным.

Следующий сценарий удаляет слово end только для $string3.

use warnings; 
use strict; 

my $string1 = " match to the end" . chr(13); 
my $string2 = " match to the end" . chr(13) . chr(10); 
my $string3 = " match to the end" .   chr(10); 

$string1 =~ s/ end$//; 
$string2 =~ s/ end$//; 
$string3 =~ s/ end$//; 

print "$string1\n"; 
print "$string2\n"; 
print "$string3\n"; 

Но я почти 75% уверен, что я видел случаи, когда $ совпавшие по крайней мере chr(13).chr(10).

Итак, что именно (и при каких обстоятельствах) соответствует совпадению атома $? только

+3

Возможно, вы читали файл в режиме ': crlf', поэтому файл содержал' chr (13) .chr (10) ', но строка, в которой вы были сопоставлены, имела только' chr (10) '. – cjm

ответ

5

$ матчей позиции перед \n/chr(10), а не перед \r/chr(13).

Это очень часто неправильно, чтобы соответствовать до newline характера (в большинстве случаев это не вызывает проблем), но быть строгим он соответствует перед «новой строки» характер , но не раньше, чем символ возврата каретки!

Regex Tutorial - Start and End of String or Line Anchors.

+1

Гош чертовы конвенции новой строки. –

+1

Действительно. Нет такой вещи, как символ 'newline'. – Borodin

+0

@Borodin, Unicode не согласен. U + 000A известен несколькими именами, включая LINE FEED и NEW LINE. – ikegami

12

Прежде всего, это зависит от того, действует или нет модификатор /m.

С /m активным, он соответствует перед символом \n или в конце строки. Это эквивалентно (?=\n|\z).

Без /m он соответствует символу \n, если это последний символ строки или в конце строки. Это эквивалентно (?=\n?\z).

Он не соответствует общей строке новой строки. Метахарактер \R (введенный в 5.10.0) делает это (но без свойства конца строки $). Вы можете заменить \R на \n в одном из предыдущих эквивалентов, чтобы получить рабочий стол $, который соответствует общей строке новой строки.

Отметьте, что \n не всегда chr(10). Это зависит от платформы. Большинство платформ, используемых в настоящее время, имеют \n, что означает chr(10), но это не всегда так. Например, на старших компьютерах Mac \n был chr(13) и \r был chr(10).

+4

Последняя часть вашего ответа вводит в заблуждение, если не просто неверно. Internally Perl * always * представляет конец строки последовательности на платформе с символом '' \ n "', который всегда * * chr (10) или ASCII 'LF'. Это идентично тому, что появляется во внешнем файле для Linux и Max OS X, но дополнительный IO-слой переводит его в и из «CR LF» на платформе Windows и DOS и «CR» в Mac OS v9 и более ранних версиях. '' \ r "' никогда не был чем-то другим, кроме 'chr (13)' или ASCII 'CR'. – Borodin

+0

@Borodin Однако нужно быть осторожным, если нужно иметь дело с файлами, созданными на другой платформе. –

+2

@ Боридин, вы ошибаетесь и cjm правильно. На сборках MacOS \ n и \ r соответствуют/производятся 0D и 0A соответственно. Вот почему есть (obselete) рекомендации использовать '\ x0D \ x0A' для вывода CGI вместо' \ r \ n'. Если то, что вы говорите, верно, эти два будут эквивалентны. Уровни PerlIO даже тогда не существовали. – ikegami

1
/$/ 
/$/m 

эквивалентны

/(?=\n\z)|\z/ 
/(?=\n)|\z/ 

соответственно. \n соответствует U + 000A (LINE FEED aka NEWLINE) на всех существующих платформах.

+0

Хотя ваши эквивалентные регулярные выражения верны, как написано, я думаю, что мои версии лучше. Поскольку '\ z' является утверждением с нулевой шириной, на самом деле не имеет значения, находится ли он внутри' (? = ...) ', но, перемещая чередование внутри группы, вы можете использовать его в расширенном регулярном выражении as- является. С вашими версиями вам нужно будет использовать '(?: (? = \ N \ z) | \ z)', чтобы '' 'чередовать больше, чем нужно. – cjm