Perl: найти точное слово из файла с разделителями табуляции

У меня есть файл с разделителями табуляции (содержащий 2 столбца) в следующем формате:

ABA-1 (tab)           CDF@
ABA-1 (tab)           EFG
ZYA (tab)             ABA-1 this
EFG that this (tab)   ZYA

Я хочу сопоставить только /EFG/, а не /EFG, что это/. Точно так же я хочу сопоставить только /ABA-1/, а не /ABA-1 this/.

Следующий шаблон не работает:

$line=~ /^(\w*\-?\w*\@?)\t*(\w*\-?\w*\@?)$/

Я пробовал использовать границы слов (\b), но это тоже не работает.

Любые идеи о том, как решить эту проблему? Любая помощь будет высоко оценена. Большое спасибо!


person zock    schedule 16.10.2012    source источник
comment
Итак, вы хотите сопоставить все символы, пока не найдете пробел? Нравится CDF@ тоже?   -  person Rohit Jain    schedule 16.10.2012
comment
Как насчет $%^2 this после Tab?   -  person Rohit Jain    schedule 16.10.2012
comment
Да, я хочу соответствовать, пока не найду место.   -  person zock    schedule 16.10.2012
comment
@RohitJain: я не понял вашего второго комментария.   -  person zock    schedule 16.10.2012
comment
Итак, fba#$@! thsi (tab) $%^ asf -> Итак, что вы хотите сопоставить в этой строке? -› fba#$@! и $%^?   -  person Rohit Jain    schedule 16.10.2012


Ответы (3)


Ваше регулярное выражение не работает по нескольким причинам. Во-первых, ваша вкладка не может быть необязательной, иначе строка не будет правильно разделена. Во-вторых, в вашем шаблоне нет ничего, что могло бы объяснить возможные символы после частей, которые вы хотите сопоставить, то есть ничего, что соответствовало бы that this.

Вы можете решить первую, добавив .*? после каждого захвата (или, для второго захвата, просто удалив конечную привязку $). Вторая проблема решается просто заменой \t* на \t.

Эта модификация работает с вашими образцами данных

$line =~ /^(\w*\-?\w*\@?).*?\t(\w*\-?\w*\@?).*?$/

но это не очень красиво!

Похоже, вам просто нужны все строки не пробельных символов сразу после табуляции или начала строки

Эта программа кодирует эту идею как регулярное выражение

use strict;
use warnings;

my @data = (
  "ABA-1\tCDF@",
  "ABA-1\tEFG", 
  "ZYA\tABA-1 this",
  "EFG that this\tZYA",
);

for (@data) {
  my @fields = /(?:^|\t)(\S+)/g;
  print "@fields\n";
}

вывод

ABA-1 CDF@
ABA-1 EFG
ZYA ABA-1
EFG ZYA
person Borodin    schedule 16.10.2012

Это будет соответствовать двум словам (без пробелов), разделенным одной табуляцией в строке:

$line=~ /^(\w+)\t(\w+)$/

Обновление: это исключит все строки, содержащие что-то вроде «ABA this». Однако, возможно, вы хотите захватить только ABA из «ABA this». Это сделает это для вас:

$line=~ /^([A-Z]+)[^\t]*\t([A-Z]+)/

Обновление: вот новый шаблон для новых требований. Он соответствует первой части без пробелов в каждом столбце.

$line=~ /^([^\s]+).*\t\s*([^\s]+)/
person dan1111    schedule 16.10.2012
comment
Пожалуйста, посмотрите на отредактированный входной файл. Я изменил его, чтобы сделать его более похожим на мой оригинальный файл. - person zock; 16.10.2012
comment
Ваш обновленный код не работает с CDF@ (строка 1, 2-й столбец) и ABA-1 this (строка 3, 2-й столбец). - person zock; 16.10.2012
comment
@zock, я проверил это, и в этих случаях совпадения возвращают CDF@ и ABA-1 соответственно. Если вы не получаете этих результатов, значит, в вашем коде есть какая-то другая проблема, или ваш файл не совсем соответствует описанию. Например, если у вас есть символ табуляции после второго столбца, это приведет к сбою. - person dan1111; 16.10.2012

$line=~ /^(\w+)[^\t]*\t(\w+).*$/

Это захватит только первое слово до и после tab.

ОБНОВЛЕНИЕ: - Если вы хотите сопоставить any non-space символа перед первым пробелом, вы можете попробовать этот шаблон: -

my $line = "ABA-1\tCDF@";
my $line1 = "ZYA \t  ABA-1 this";

if ($line=~ /^([^\s]+)[^\t]*\t\s*([^\s]+).*$/) {    
    print "$1 $2";
}

if ($line=~ /^([^\s]+)[^\t]*\t\s*([^\s]+).*$/) {    
    print "$1 $2";
}

ВЫВОД: -

ABA-1 CDF@
ZYA ABA-1
person Rohit Jain    schedule 16.10.2012
comment
Это не будет работать для строк, которые содержат только одно слово на каждой стороне вкладки. Это разбило бы ABA в первой строке, например, на AB и A, и вернуло бы только AB в качестве совпадения. - person dan1111; 16.10.2012
comment
Пожалуйста, посмотрите на отредактированный входной файл. Я изменил его, чтобы сделать его более похожим на мой оригинальный файл. - person zock; 16.10.2012
comment
Ну, согласно предоставленной вами схеме, я хочу соответствовать 34%! (вкладка) %^#. - person zock; 16.10.2012
comment
Ваш обновленный код не работает с CDF@ (строка 1, 2-й столбец) и ABA-1 this (строка 3, 2-й столбец). - person zock; 16.10.2012
comment
Во 2-м столбце может быть пробел, например: ABA-1 (пробел) это. - person zock; 16.10.2012
comment
Двойная обратная косая черта предотвращает совпадение шаблонов с символом табуляции: вам нужно просто \t. Также нет необходимости захватывать вкладку - вы ведь знаете, что это такое! - person Borodin; 16.10.2012
comment
@Borodin Ну, я попробовал это в Eclipse, но это не соответствует \t, а \\t - person Rohit Jain; 16.10.2012
comment
@RohitJain, причина, по которой у вас возникли проблемы с сопоставлением вкладок, заключается в том, что в приведенном выше примере кода используются строки в одинарных кавычках. Таким образом, ваши тестовые данные на самом деле не имеют вкладок; это буквально '\t'. Вот почему вам нужна двойная обратная косая черта, чтобы соответствовать ему. Исправьте это, используя двойные кавычки для ваших тестовых данных. - person dan1111; 16.10.2012
comment
@dan1111 А! Спасибо, Дэн. Я там чуть не заблудился.. :) - person Rohit Jain; 16.10.2012
comment
@Borodin Не могли бы вы удалить свой отрицательный голос, если текущий шаблон в порядке? - person Rohit Jain; 16.10.2012