Hello!

I need help whith perl.

I have 2 files, i whant to open them compare une colun and if they iqual i whant to write at the 1ª file some coluns of the secund file.

Exemple:
File 1

2; apartamento; T2; manuel; 120.000€; Activo
4; moradia; V4;José; 250.000€; Suspenso

File 2
12; manuel; arcozelo; 234567888; activo
23; josé; Londres;004444444;Activo

Result
2; apartamento; T2; manuel; 234567888; 120.000€; Activo
4; moradia; V4;José; 004444444; 250.000€; Suspenso

Can you help me please.

Inês

Dani AI

Generated

A robust, maintainable approach is to build a lookup from file2 keyed by a canonical form of the person name, then stream file1 and inject the phone when a match exists. That avoids brittle line-index matching (which assumes both files line up) and follows the hash idea suggested by , but with some important improvements: do not strip all whitespace (that destroys multi-word fields), handle accents/Unicode and case consistently, and treat duplicate names explicitly instead of silently overwriting.

Practical checklist:

  • Use lexical filehandles and three-arg open; set an encoding on I/O so accented names are handled correctly.
  • Split on semicolons while preserving internal spaces (e.g. split /\s*;\s*/), and trim only leading/trailing whitespace for each field.
  • Normalize names with Unicode normalization (NFC) and Unicode casefolding so "Jose", "josé" and "JOSÉ" map to the same key.
  • Store phone(s) in the lookup as arrayrefs so duplicates are preserved and can be resolved by chosen criteria (first match, prefer active entries, or use composite keys).

A compact, practical example (uses Unicode normalization and keeps duplicates):

use strict;
use warnings;
use utf8;
use open ':std', ':encoding(UTF-8)';
use Unicode::Normalize;

sub norm {
  my $s = shift // '';
  $s = NFC($s);
  $s = eval { fc($s) } // lc($s);
  $s =~ s/^\s+|\s+$//g;
  return $s;
}

my %phones;
open my $f2, '<:encoding(UTF-8)', 'f2.txt' or die $!;
while (<$f2>) {
  chomp;
  my @f = split /\s*;\s*/;
  push @{ $phones{ norm($f[1]) } }, $f[3] if defined $f[1] && defined $f[3];
}
close $f2;

open my $in1, '<:encoding(UTF-8)', 'f1.txt' or die $!;
open my $out, '>:encoding(UTF-8)', 'result.txt' or die $!;
while (<$in1>) {
  chomp;
  my @f = split /\s*;\s*/;
  my $key = norm($f[3] // '');
  if (my $list = $phones{$key}) {
    my $phone = $list->[0];    # selection strategy can be improved
    print $out join('; ', $f[0], $f[1], $f[2], $f[3], $phone, $f[4], $f[5]) . "\n";
  }
}
close $in1;
close $out;

Operational tips: if fields can contain quoted semicolons, use Text::CSV_XS with sep_char => ';'. To disambiguate duplicates, key on an extra column (name+location) or keep all matches and log ambiguous rows. Use atomic writes (write to a temp file and rename) and check for BOM/encoding issues before processing. This will make the merge reliable across accents, spacing quirks, and inconsistent case.

Recommended Answers

All 5 Replies

Clumsy, but it works:

use strict;
use warnings;

my @pf1;
open(F1,"<f1.txt");

while(<F1>){
	my @f1;
	chomp;
	s/\s+//g;
	(@f1)=split(/\;/);
	push (@pf1,\@f1);
}
close F1;
my @f2;
open (OUT,">result.txt");
open(F2,"<f2.txt");
my $x=0;
while(<F2>){
	chomp;
	s/\s+//g;
	(@f2)=split(/\;/);
	$f2[1] = 0 if(!$f2[1]);
	$pf1[$x][3]=0 if(!$pf1[$x][3]);
	if($f2[1] eq "\L$pf1[$x][3]"){
		print OUT "$pf1[$x][0]\; $pf1[$x][1]\; $pf1[$x][2]\; $pf1[$x][3]\; $f2[3]\; $pf1[$x][4]\; $pf1[$x][5]\;\n";
	}
	$x++;
}
close F2;
close OUT;

thanks!
works well but i does not quite understand the code from the line 23 to the end.
Can explain me better?

What I did was push an array reference into another array. Each element of the first file was split into an array @f1. Then I pushed a reference to that array into @pf1, so each element of the array @pf1 is an array reference (or a pointer to the memory space of the array @f1, but since I let it go out of scope, it becomes a pointer to an anonymous array). So, when I compare the columns:

$f2[1] eq "\L$pf1[$x][3]"

I am comparing the 2nd column of file #2 (stored in @f2) with the 4th column of the same line of file #1. The \L makes the contents lowercase, because I noticed case was mixed in the files. If the lines of each file do NOT align (meaning you want to compare with something anywhere in the second file), you will have to create a hash. My suggestion is that you create a hash with the first name (column #2 in file #2) with the value of the phone number (which you print). If the value exists in the hash, print out your line. However, this will be a problem if you have duplicate names, in which case you will have to match on more than one column.

If you look back in the forum, you will see several similar solutions to such a problem.

Can you give me sonething more simple?

More simple:

use strict;
use warnings;
my %hold;
open(F2,"<f2.txt");
while(<F2>){
	chomp;
	s/\s+//g;
	my($num,$name,$unknown,$phone,$status)=split(/\;/);
	$hold{$name}=$phone;
	print "$name\n";
}
close F2;

open(OUT, ">results.txt");
open(F1,"<f1.txt");
while(<F1>){
chomp;
	s/\s+//g;
	my ($num,$something,$else,$name,$cost,$status)=split(/\;/);
	$name="\L$name";
	if($hold{$name}){
		print OUT "$num\; $something\; $else\; $name\; $hold{$name}\; $cost\; $status\;\n";
	}
	
}
close F1;
close OUT;
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.