2012-12-10 1 views
-1

название может ввести в заблуждение, вот что я пытаюсь сделать:Матч строки из File1 в Файл2 и заменить строку в File1 с соответствующими найденную строку в Файл2

File1 
12=921:5,895:5,813:5,853:5,978:5,807:5,1200:5,1067:5,827:5 

File2 
Tom 12 John 921 Mike 813 

Output 
Tom=John:5,Mike:5 

file2 имеет значения чисел в файле1, и я хочу совместить и заменить числа на строковые значения. Я пробовал это с моими ограниченными знаниями в awk, но не мог этого сделать.

Любая помощь приветствуется.

+0

@kikumbob Я попытался разбить строку в файле1, используя метрику ':' и '=', и сопоставить в файле 2, но не смог заменить его соответствующим столбцом. – Kaartz

+0

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

ответ

1

Вот один из способов использования GNU awk. Бегите как:

awk -f script.awk file1 file2 

Содержание script.awk:

BEGIN { 
    FS="[ =:,]" 
} 

FNR==NR { 
    a[$1]=$0 
    next 
} 

$2 in a { 
    split(a[$2],b) 
    for (i=3;i<=NF-1;i+=2) { 
     for (j=2;j<=length(b)-1;j+=2) { 
      if ($(i+1) == b[j]) { 
       line = (line ? line "," : "") $i ":" b[j+1] 
      } 
     } 
    } 
    print $1 "=" line 
    line = "" 
} 

Результаты:

Tom=John:5,Mike:5 

В качестве альтернативы, вот один вкладыш:

awk -F "[ =:,]" 'FNR==NR { a[$1]=$0; next } $2 in a { split(a[$2],b); for (i=3;i<=NF-1;i+=2) for (j=2;j<=length(b)-1;j+=2) if ($(i+1) == b[j]) line = (line ? line "," : "") $i ":" b[j+1]; print $1 "=" line; line = "" }' file1 file2 

Объяснение:

Изменить разделитель полей awk на пробел, равный, двоеточие или запятую.

'FNR == NR {...}' относится только к первому файлу в списке аргументов.

Итак, при обработке файла1 awk добавит столбец «1» к массиву, и мы назначим всю строку как значение этому элементу массива.

'next' просто пропустит обработку остальной части скрипта и прочитает следующую строку ввода.

Когда awk закончил чтение ввода в файле1, он продолжит чтение файла2. Однако это также сбрасывает «FNR» на «1», поэтому awk пропустит обработку блока «FNR == NR» для файла2, потому что он больше не верен.

Так что для file2: если столбец «2» может быть найден в массиве упомянутой выше:

разбить значение элемента массива в другой массив. Это по существу разделяет всю строку в файле1.

Теперь создайте две петли.

Первый цикл будет через все имена в file2

И второй будет перебрать все значения в (второй) массив (это в основном цикле по всем полям в file1).

Теперь, когда значение сменив имя в file2 равно одному из ключевых чисел в file1, создать конструкцию строки, которая выглядит следующим образом: «имя: number_following_key_number_from_file1».

Когда во время циклов найдено больше имен и значений, четвертичная конструкция '(...? ...: ...)' добавляет эти элементы в конец строки. Это как утверждение if; если есть уже строка, добавьте запятую на ее конец, иначе ничего не делайте.

Когда все петли завершены, распечатайте столбец «1» и линию. Затем очистите переменную строки так, чтобы ее можно было использовать снова.

HTH. Удачи.

+0

Большое спасибо, Стив. Было бы здорово, если бы вы могли объяснить мне код. – Kaartz

+0

@ Kaartz: проблем нет. Я добавил немного объяснений. Если есть концепция, которую я не закрыл, дайте мне знать, и я могу попытаться объяснить ее еще немного. НТН. – Steve

+0

Большое спасибо за объяснение. – Kaartz

0

Следующее может работать в качестве шаблона:

[email protected] ~/ perl -e '$values="12=921:5,895:5,813:5,853:5,978:5,807:5,1200:5,1067:5,827:5"; 
$data = "Tom 12 John 921 Mike 813"; 
($line,$values)=split/=/,$values; 
@values=split/,/,$values; 
$values{$line}="="; 
map{$_=~/(\d+)(:\d+)/;$values{$1}="$2";}@values; 
if ($data=~/\w+\s$line\s/){ 
    $data=~s/(\w+)\s(\d+)\s?/$1$values{$2}/g; 
} 
print "$data\n"; 
' 
Tom=John:5Mike:5 
[email protected] ~/ 
Смежные вопросы