2013-09-30 3 views
6

может кто-нибудь объяснить это странное поведение: путь ХаваPerl разделить интересное поведение

I в строке, и я хочу, чтобы разбить его на каждой обратной косой черты

my $path = "D:\Folder\AnotherFolder\file.txt"; 

my @folders = split('\', $path); 

в предыдущем случае он не будет работать, не даже если избежать обратной косой черты, как это:

my @folders = split('\\', $path); 

, но в случае регулярного выражения будет работать:

my @folders = split(/\\/, $path); 

Почему так?

+2

Ваши побеги на пути неправильны. В строке с двойными кавычками '\ Folder' интерпретируется как escape-последовательность' \ F'. – TLP

+4

Плохая практика использовать кавычки вокруг шаблона разделителя для 'split', так как она не выражает семантику правильно и вызывает двойную компиляцию. Всегда используйте косые черты, если вы не хотите передавать однопространственную строку, чтобы вызвать поведение по умолчанию, когда '' '' является правильным выбором. – Borodin

+0

@TLP Да, я знаю, я обычно ставил только одиночные кавычки для пути. спасибо –

ответ

2

Если вы посмотрите на документацию, выполнив:

perldoc -f split 

вы увидите три формы аргументов, которые split могут принять:

split /PATTERN/,EXPR,LIMIT 
split /PATTERN/,EXPR 
split /PATTERN/ 

Это означает, что даже тогда, когда вы проходите split строку, как первый аргумент, perl принуждает его к регулярному выражению.

Если мы посмотрим на предупреждения, которые мы получаем при попытке сделать что-то подобное в re.pl:

$ my $string_with_backslashes = "Hello\\there\\friend"; 
Hello\there\friend 
$ my @arry = split('\\', $string_with_backslashes); 
Compile error: Trailing \ in regex m/\/ at (eval 287) line 6. 

мы видим, что первое, '\\' интерполируется как обратный слэш бегству с последующей фактической обратной косой черты, которая принимает значение один обратный слэш.

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

$ my @arry = split(/\/, $string_with_backslashes); 

, который не работает, потому что есть только один обратный слэш, который интерпретируется как просто избежать передняя косая черта после него (без окончания /), чтобы показать, что регекс закончился.

+0

На самом деле, если бы он избежал косой черты, вы получили бы ошибку «шаблон поиска не завершен», то есть оператор был сломан , Это нечто другое. – TLP

+3

более явно: строки и регулярные выражения имеют разные правила для экранирования. Если вместо регулярного выражения используется строка, строковые литералы подвергаются двойному экранированию. – amon

+0

@ user1436026 Я прочитал perldoc, но не мог полностью понять внутреннюю работу, не знал, что все, что вы вкладываете в '', все еще попадает в regexp –

5

Я думаю amon дал лучший буквальный ответ на свой вопрос в своем комментарии:

более явно: строки и регулярные выражения имеют разные правила для побега. Если строка используются вместо регулярных выражений, строковые литералы страдают от двойного побега

Это означает, что split '\\' использует строку и split /\\/ использует регулярное выражение.

В качестве практического ответа, я хотел бы добавить следующее:

Возможно, вам следует рассмотреть возможность использования модуля подходит для разделения путей. File::Spec является основным модулем в Perl 5. Кроме того, вам нужно избегать обратной косой черты в двойной кавычки, которую вы еще не сделали. Вы также можете использовать одинарные кавычки, которые выглядят немного лучше, на мой взгляд.

use strict; 
use warnings; 
use Data::Dumper; 
use File::Spec; 

my $path = 'D:\Folder\AnotherFolder\file.txt'; # note the single quotes 
my @elements = File::Spec->splitdir($path); 
print Dumper \@elements; 

Выход:

$VAR1 = [ 
      'D:', 
      'Folder', 
      'AnotherFolder', 
      'file.txt' 
     ]; 
+0

спасибо за подсказку с файлом :: Spec –

+0

@AndreiDoanca правильный инструмент для расщепления путей, и он переносимый и надежный. Я не уверен, что вы пытаетесь сделать, разделив путь, но он похож на XY-проблему. – TLP

+0

на самом деле это не XY-проблема, просто любопытство мое :) –

2

Один из способов аккуратнее, чтобы извлечь элементы пути, чтобы извлечь все последовательности символов, отличных от путь сепаратора.

use strict; 
use warnings; 

my $path = 'D:\Folder\AnotherFolder\file.txt'; 
my @path = $path =~ m([^/\\]+)g; 

print "$_\n" for @path; 

выход

D: 
Folder 
AnotherFolder 
file.txt 
2

Когда split используется в виде split STRING и не split REGEX, строка преобразуется в регулярное выражение. В вашем случае split '\\' будет преобразован в split /\/, поскольку первая обратная косая черта считается escape-символом.

Правильный способ сделать это split '\\\\', который будет переведен на split /\\/.

+0

спасибо за объяснение, действительно хорошая информация :) Я понимаю сейчас и вижу, что это работает :) –

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