[求助]如何改写文件中特定位置的字符

[求助]如何改写文件中特定位置的字符

需要处理多个xml文件,这些文件的第二行为
<!DOCTYPE bbs SYSTEM "http://bbs.chinaunix.net/xml/model.dtd">
我需要把它改写为
<!DOCTYPE bbs SYSTEM "d:\data\model.dtd">,
文件中的其他内容不变
写程序如下:
open XML, "+<".$xml || die "$!\n";

my $old = 'http://bbs.chinaunix.net/xml/';
my $new = 'd:\data\';

<XML>;                          ##omit the first line
my $currentpos = tell;   ##如果不同tell和seek重新定位,直接print,就写到了文件后面某个未知的位置,这点也不明白
my $dtd = <XML>;
$dtd =~ s/$old/$new/o;
seek(XML,$currentpos,0);
print XML $dtd;

close XML;

程序运行的结果,
<?xml version="1.0"?>
<!DOCTYPE bbs SYSTEM "d:\data\model.dtd">
   #多了一个空行
t/xml/model.dtd">
.....#后面都正常了。
我知道这是因为$new和$old长度不一样所导致的,但是怎么解决这个问题呢(不print整个文件,只修改这一行),只把model.dtd前面的目录改变其他都不变,请高人指教!
刚试了下,下面这句可以把所由.pl的文件的第一行的perl改为www.

perl -pi -e 's/perl/www/ if($. = 1)' *.pl  

不知道这句你用的着不.

perl -pi -e 's#http://bbs.chinaunix.net/xml/#d:\data\# if($. = 2)' *.xml

use Tie::File;


QUOTE:
原帖由 kgd924 于 2007-10-11 16:35 发表
刚试了下,下面这句可以把所由.pl的文件的第一行的perl改为www.

perl -pi -e 's/perl/www/ if($. = 1)' *.pl  

不知道这句你用的着不.

perl -pi -e 's#
use Tie::File;

谢谢Lonki, Tie::File只是把文件内容绑定了一个数组,我现在取文件内容和定位不是问题,可是输出就出问题。
如果只是简单的另
$arry[2]='<!DOCTYPE bbs SYSTEM "D:\Data\model.dtd">';
然后untie @arry的话,
这一句输出在整个文件末尾之后的第二行,甚至在untie前面加了seek(XML,0,0)重新定位指针也不管用。
如下:

end#文件末尾

<!DOCTYPE bbs SYSTEM "D:\Data\model.dtd">


只好再请问,Tie::File之后怎么输出才能把正文第二行全部清空并把新内容写入呢?

呵呵,,,不知你的需求是什么,如果只是为了显示xml, 也许可以作"http://bbs.chinaunix.net/xml/model.dtd" 的映射. (我看到jbuider有这个功能)我想XML语法分析器也可以.
今天刚在学xml, 也许你问题不需要埃个的替换.
我需要从xml文件中提取数据,dtd是模板,因为dtd文件在网上,不如本地取省时间,所以我想把它的目录改一下。改目录不是最终目的,而是调用它来读取xml的数据。我想用XML::LibXML的语法分析器,我也是刚学,好多不懂
这么奇怪? 上code吧

按你的需要, 确实只需要简单的修改数组的一个元素

另: 第2行应是$array[1];
     这个数组均不包含行结尾的\n的



QUOTE:
原帖由 Lonki 于 2007-10-11 18:42 发表
这么奇怪? 上code吧

按你的需要, 确实只需要简单的修改数组的一个元素

另: 第2行应是$array[1];
     这个数组均不包含行结尾的\n的

Lonki, 第2行是$arry[2],cpan的Tie::File是这么说的,我的测试结果也是这样;

这是我的测试代码:
#!/usr/bin/perl -w

use strict;
use Tie::File;

my $filename = "D:\\Data\\test.xml";
tie my @arry,'Tie::File', $filename or die "Couldn't tie!\n";

$arry[2] ='<!DOCTYPE sub SYSTEM "D:\Data\model.dtd">';

seek (XML,0,0);  ##加不加效果一样;

untie @arry;


#test.xml文件内容:
#
<?xml version="1.0"?>
<!DOCTYPE bbs SYSTEM "http://bbs.chinaunix.net/model.dtd">
<!-- Creation date: Aug 22 2007 02:35:48 +0900 (JST) -->
#。。。后略
#end

#结果:
#
<?xml version="1.0"?>
<!DOCTYPE bbs SYSTEM "http://bbs.chinaunix.net/model.dtd">
<!-- Creation date: Aug 22 2007 02:35:48 +0900 (JST) -->
#。。。后略
#end

<!DOCTYPE bbs SYSTEM "D:\Data\model.dtd">

貌似Tie::File不能在原文上修改啊

刚测了你的代码和input, 一切正常.

并且:
<?xml version="1.0"?> ### $array[0]
<!DOCTYPE bbs SYSTEM "http://bbs.chinaunix.net/model.dtd"> ### $array[1]
<!-- Creation date: Aug 22 2007 02:35:48 +0900 (JST) --> ### $array[2]

cpan原文我也去看了下, 原文:
The first line of the file is element 0 of the array; the second line is element 1, and so on.


PS: 在原文件上编辑行, 删除行, 添加行, 就是Tie::File的主要作用

奇怪了,怎么到我这儿就不行了呢,是不是跟文件属性也有关系啊?
另外,关于$arry[1]的问题,cpan的Tie::File页面上有这么句话啊:
$array[13] = 'blah';     # line 13 of the file is now 'blah'
不是说第十三行被改了么?而且我输出的结果,写作$arry[2]的时候前面的确有空行而写作$arry[1]前面就没空行了呀