使用DBMS_OUTPUT遍历文本时出现奇怪的输出

时间:2018-09-04 12:53:29

标签: sql oracle plsql plsqldeveloper

我正在编写一些代码来接受输入字符串,并以多行形式输出以满足特定的行长,我还需要它始终以新单词开始新行,以便单词在行与行之间不会重叠,从而很难阅读。

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

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我知道我在最后一行的末尾缺少一些字符,但这又是一个问题。

4 个答案:

答案 0 :(得分: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

答案 1 :(得分:0)

在此处添加TRIM

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

答案 2 :(得分:0)

Trim适用于您的情况:

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;

希望这会有所帮助。

答案 3 :(得分: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;

输出:

  

好吧,王子,所以热那亚和卢卡现在只是   Buonapartes。但是我警告你,如果你不告诉我这意味着战争,   如果您仍要捍卫由...造成的家庭和恐怖   我真的相信他是敌基督者