关于打印中英文混合文本时的换行问题!(300分)

  • 主题发起人 Luis Pater
  • 开始时间
L

Luis Pater

Unregistered / Unconfirmed
GUEST, unregistred user!
我是直接使用Printer组件打印的!什么建议我用其他报表软件打印就不用回复了!
我用的方式是计算字节数,然后截断换行打印,估计是中英文混合的文本中,英文文字成单数,所以截断了的最后一个汉字的后半部分与之后一行下一个汉字的前半部分组成了乱码!我附上了我的算法!也许太简单了!呵呵……大家帮我看看吧!
tLine:=(Length(SettleMemo.Lines.Text) div 72);
for I:=0 to tLinedo
begin
TTextOut(350,960+50*I,Copy(SettleMemo.Lines.Text,I*72+1,72),'宋体',11);
end;
TTextOut是我自己写的函数,用于精确打印0.1毫米的文本!呵呵……我也在这里附上吧:
function TTextOut(XMM,YMM:integer;Str,FontName:String;FontSize:Integer):Boolean;
var
dpix,dpiy:integer;
X,Y:integer;
begin
dpix:=GetDeviceCaps(Printer.Handle,LogPixelsX);//获取横向打印分辨率
dpiy:=GetDeviceCaps(Printer.Handle,LogPixelsY);//获取纵向打印分辨率
Printer.Canvas.Font.Name:=FontName;
Printer.Canvas.Font.Size:=FontSize;
X:=Round((LeftRight+XMM)/254*dpix);
Y:=Round((TopEnd+YMM)/254*dpiy);
Printer.Canvas.TextOut(X,Y,Str);
Result:=True;
end;
麻烦大家了!挺着急的!希望大家能给我满意的解答!:)谢谢!
 
怎么没人回答呢??我提一下!
 
我也遇到过此类问题,我读了字符串内所有的字符,汉字和字符的AscII(用ord试一下)是不同的,你的程序能简单一点,只需要在换行处(第72个字符处)判断一下,就能解决问题,虽然是个笨方法,我也只好如此,看看高手还有什么方法。
 
可能是你的算法太简单了。你可以考虑:
一、先算出一行能显示X个字符。
二、把字符串分行,从第一个字符起取每一字符,判断是不是英文字符,这时可设置一个布尔变量初始化为true,如果当前字符是汉字字符且变量为true时则令为false否则为true,为英文字符则令为true,算到第X个字符时,则根据变量为true还是false判断是否多取一个字符或少取一个字符。
 
嘿嘿,我以前遇到的问题,我没细看你的程序,不过我以前是这样解决的,将STRING全部转换成WIDESTRING就可以了。GOOD LUCK。
 
whhtao笑得有道理,改为WIDESTRING后,的确不会截错中文字符了(多谢whhtao,又学会了一招)。
但若要凭此解决楼主的问题,还不是那么简单,因为在WIDESTRING中的字符,每一个汉字和每一个西文字符都是当一个字符看待的,势必造成最后截取到的字符个数与想象的不一样,比如:
var
s:widestring;
s2:string;
begin
s2:=copy(s1,1,4);
end;
假设s:='中华人民共和国'
则s2:='中华人民',共8个字符;
假设s:='123中华人民共和国'
则s2:='123中',共5个字符;
可以预计,打印结果的宽度肯定不一样。
 
在此想说一种解决的方法:
1、delphi将中文看为两个字符,其ascii码都>128。
2、在定好每行字数后,对最后一个字判断其ascii码是否<128,如果大于则前移一位。
3、具体算法自己练,呵呵!
 
用手动最理想
 
这样试试
// tLine:=(Length(SettleMemo.Lines.Text) div 72);
p := 1;
LineLen := LineLen(SettleMemo.Lines.Text));
while p <= LineLendo
begin
Len := 72;
if not CunOK(copy(SettleMemo.Lines.Text,p,len)) then
Dec(Len);
TTextOut(350,960+50*I,Copy(SettleMemo.Lines.Text,p,Len),'宋体',11);
inc(p,Len);
end;
 
to gydldfw:
1、delphi将中文看为两个字符(字符串为string型时),其ascii码都>159。
2、在定好每行字数后,对最后一个字判断其ascii码是否<160,如果大于则前移一位(当它是汉字的第一个字符时,如果是第二个字符时?当然,我假定“前移”是向第一个字符的方向,另一个方向也同理,我认为不从头读起,是很难解决的,不过在我的印象中,似乎有一个函数可以判断是不是一个汉字的第一个字节的,但还没找到)。
我也认为手动是最理想的办法,如果可以用剪刀的话,应该比编程快些。

 
同意lhc4000做法,我有試過
 
我试验了一下WIDESTRING,长短就不去说了!又有一个问题出来了!就是Memo不能有回车符,否则最后一行的代码势必会出现乱码的情况……
大家帮我试试看!解答成功了!我再给大家300分!谢谢了!
 
最近比较痛苦一点,一个人要写三个程序,两个Delphi的!一个PHP的!工作量比较大,所以不太愿意去项具体的算法了……哎……人啊!就是懒……[:(]
 
回车符也是两个字符#13/#10是不是这个原因呢?
把这两个字符替换掉吧
 
一、
动态生成一个TMEMO或TRICHEDIT,令其WORDRAP=TRUE,并设置其宽度(正好容纳N个汉字),
然后将文本装入,再逐行复制到指定处即可;
二、
if (ByteType(s,length(s))=mbLeadByte) or (ByteType(s,length(s))=mbTrailByte) then
begin
//是汉字的前半节 或 汉字的后半节
end else
begin
//是单字节字符
end;
这个函数好像很少人提到,但能准确判断出一个字符是单字节字符还是双字节字符。楼上有
人说用ascii值大于多少判断,但好像有时会出问题,不准确。
 
个人觉得不是!我在3个字节的地方用回车也会有乱码!
不过我现在想想,回车应该替换掉,然后增加行数才对的![:)]
 
问题是怎么替换回车符?这个以前倒没做过……
 
同意iseek的,我也刚找到了此函数
 
procedure TForm1.Button1Click(Sender: TObject);
var
p : integer;
str, rstr : string;
s : string;
begin
str := memo1.Text;
rstr := '';
s := char(13) + char(10);
p := pos(s, str);
while p > 0do
begin
rstr := rstr + copy(str, 1, p - 1);
str := copy(str, p + 2, length(str) - p - 1);
p := pos(s, str);
end;
memo1.Text := rstr + str;
end;
再转换成WIDESTRING
写成了函数
function TForm1.delr(istr : string): string;
var
p : integer;
str, rstr : string;
s : string;
begin
str := istr;
rstr := '';
s := char(13) + char(10);
p := pos(s, str);
while p > 0do
begin
rstr := rstr + copy(str, 1, p - 1);
str := copy(str, p + 2, length(str) - p - 1);
p := pos(s, str);
end;
Result := rstr + str;
end;
 
你打印时不用依靠识别回车来换段吗?把回车都换掉了,你怎么知什么时候另起一段?
 

Similar threads

顶部