使用DBMS_OUTPUT循环文本时输出奇怪

问题描述 投票:0回答:4

我正在编写一些代码来获取输入字符串并将其输出为多行以满足特定的行长度,我还需要它始终以新单词开始新行,因此单词之间不会重叠,使其难以阅读。

这可能不是最好的方法,但这是我想出来的;

DECLARE
P_output_record          VARCHAR2(1000) := 'Well, Prince, so Genoa and Lucca are now just family estates of the Buonapartes. But I warn you, if you dont tell me that this means war, if you still try to defend the infamies and horrors perpetrated by that Antichrist I really believe he is Antichrist';
v_message_length         INTEGER;
v_written_chars          INTEGER;
v_new_line               VARCHAR2(30);
v_chars_to_write         INTEGER;
BEGIN
dbms_output.enable();
v_message_length := LENGTH(P_output_record);
v_written_chars := 0;

   WHILE(v_written_chars < v_message_length)
   LOOP
      IF(v_written_chars + 28 > v_message_length) THEN
        v_chars_to_write := (v_message_length - v_written_chars);
        v_new_line := SUBSTR( P_output_record, v_written_chars, v_chars_to_write);
      ELSE
        v_new_line := SUBSTR( P_output_record,v_written_chars, 28);
        --get the index of the last space so words dont spill to new lines
        v_chars_to_write := INSTR(v_new_line,' ', -1);
      END IF;
      DBMS_OUTPUT.PUT_LINE( SUBSTR( P_output_record, v_written_chars, v_chars_to_write-1));
      v_written_chars := v_written_chars + v_chars_to_write; 
   END LOOP;
END;

这有效,因为每一行都以一个新单词开头,单词不会溢出。然而输出有点奇怪,第二行现在重要的是空间,或者整个文本总是以空格开头,我尝试将这些单词合并在一起,但它只是事先从空间开始(但是嘿那是预期)甚至尝试了不同的文本,但仍然得到第二行以空格开头的相同结果,这表明我的逻辑有问题,但我会假设如果这是我的逻辑那么它会发生在其他行上它也没有。

在这里看到第二行之前是否有空格。

Well, Prince, so Genoa and
 Lucca are now just family
estates of the Buonapartes.
But I warn you, if you dont
tell me that this means
war, if you still try to
defend the infamies and
horrors perpetrated by that
Antichrist I really believe
he is Antichri

P.S我知道我在最后一行的末尾错过了一些字符,但这是另一个问题。

sql oracle plsql plsqldeveloper
4个回答
1
投票

问题在于,您使用v_written_chars来计算已编写的字符数,并生成剩余部分的子字符串。

在第一次迭代v_written_chars = 0v_chars_to_write = 27,所以当你这样做

v_written_chars := v_written_chars + v_chars_to_write;

你得到v_written_chars = 27

在第二次迭代中,您从第27个字符开始创建子字符串,这是一个空格,从而获得带有前导空格的字符串。

编辑代码的简单方法可以是初始化

v_written_chars = 1;

通过此编辑,结果为:

Well, Prince, so Genoa and
Lucca are now just family
estates of the Buonapartes.
But I warn you, if you dont
tell me that this means
war, if you still try to
defend the infamies and
horrors perpetrated by that
Antichrist I really believe
he is Antichri

关于字符串的最后一部分,一旦你在最后一行,你不需要计算要写的字符数,但你可以简单地做:

v_new_line := SUBSTR( P_output_record, v_written_chars);

通过编辑,您的代码变为:

...
BEGIN
dbms_output.enable();
v_message_length := LENGTH(P_output_record);
v_written_chars := 1;

   WHILE(v_written_chars < v_message_length)
   LOOP
      IF(v_written_chars + 28 > v_message_length) THEN
        v_new_line := SUBSTR( P_output_record, v_written_chars);
      ELSE
        v_new_line := SUBSTR( P_output_record,v_written_chars, 28);
        --get the index of the last space so words dont spill to new lines
        v_chars_to_write := INSTR(v_new_line,' ', -1);
      END IF;
      DBMS_OUTPUT.PUT_LINE( SUBSTR( P_output_record, v_written_chars, v_chars_to_write-1));
      v_written_chars := v_written_chars + v_chars_to_write; 
   END LOOP;
END;

结果是:

Well, Prince, so Genoa and
Lucca are now just family
estates of the Buonapartes.
But I warn you, if you dont
tell me that this means
war, if you still try to
defend the infamies and
horrors perpetrated by that
Antichrist I really believe
he is Antichrist

0
投票

添加TRIM,在这里:

DBMS_OUTPUT.PUT_LINE( trim(SUBSTR( P_output_record, v_written_chars, v_chars_to_write-1)));

0
投票

修剪将适用于您的情况:

set serveroutput on;
DECLARE
P_output_record          VARCHAR2(1000) := 'Well, Prince, so Genoa and Lucca are now just family estates of the Buonapartes. But I warn you, if you dont tell me that this means war, if you still try to defend the infamies and horrors perpetrated by that Antichrist I really believe he is Antichrist';
v_message_length         INTEGER;
v_written_chars          INTEGER;
v_new_line               VARCHAR2(30);
v_chars_to_write         INTEGER;
BEGIN
dbms_output.enable();
v_message_length := LENGTH(P_output_record);
v_written_chars := 0;

   WHILE(v_written_chars < v_message_length)
   LOOP
      IF(v_written_chars + 28 > v_message_length) THEN
        v_chars_to_write := (v_message_length - v_written_chars);
        v_new_line := SUBSTR( P_output_record, v_written_chars, v_chars_to_write);
      ELSE
        v_new_line := SUBSTR( P_output_record,v_written_chars, 28);
        --get the index of the last space so words dont spill to new lines
        v_chars_to_write := INSTR(v_new_line,' ', -1);
      END IF;
      --See this line****************Edited line*************
      DBMS_OUTPUT.PUT_LINE( trim(SUBSTR( P_output_record, v_written_chars, v_chars_to_write-1)));
      v_written_chars := v_written_chars + v_chars_to_write; 
   END LOOP;
END;

希望这可以帮助。


0
投票

将它们放在一起只是为了好玩,您还可以执行以下操作(每行使用80个字符,但更改为您想要的任何内容)。它还将多个空间压缩到一个空间:

select listagg(val, ' ') within group (order by levl)
from (
    with t as (
      select 'Well, Prince, so Genoa and Lucca are now just family estates of the Buonapartes. But I warn you, if you dont tell me that this means war, if you still try to defend the infamies and horrors perpetrated by that Antichrist I really believe he is Antichrist' as str
      from dual )
    select levl, val, trunc(running_count/80)+1 as line
    from (
        select level as levl, regexp_substr(str,'[^ ]+',1,level) as val, sum(length(regexp_substr(str,'[^ ]+',1,level))) over (order by level) as running_count
        from t
        connect by regexp_substr(str,'[^ ]+',1,level) is not null
    )
)
group by line;

输出:

好吧,Prince,所以热那亚和卢卡现在只是Buonapartes的家庭庄园。但我警告你,如果你不告诉我这意味着战争,如果你仍然试图捍卫那个敌基督者所犯的耻辱和恐怖我真的相信他是敌基督者

© www.soinside.com 2019 - 2024. All rights reserved.