Quebra de Linha em um texto

Dúvidas, dicas e truques de PL/SQL. Aqui também vão assuntos relacionados a pacotes, triggers, funções, Java-Stored Procedures, etc
Responder
danielsimbra
Rank: Estagiário Pleno
Rank: Estagiário Pleno
Mensagens: 7
Registrado em: Qui, 18 Nov 2010 10:12 am
Localização: Rio de Janeiro

Bom dia..

Estou com um problema pra resolver e gostaria de saber se alguém pode me ajudar..

Tenho um relatório, gerado em um arquivo texto por uma procedure. A linha da descrição (string) no arquivo-texto possui limite de 45 caracteres. Acontece de alguns textos virem maiores que isso então o arquivo-texto automaticamente "quebra" pra uma linha de baixo quando passa de 45 caracteres e assim por diante..

O problema é que quando exatamente na posição 45 do texto, cair no meio de uma palavra, metade desta palavra cai pra linha de baixo. (ex: PALAVRA, ficaria, PALA --> VRA iria pra linha de baixo), assim o texto fica meio desfigurado.

A idéia é quando cair em casos assim, eu mover a palavra inteira para a linha de baixo..

Estou tendo enormes dificuldades pra fazer isso acontecer, se alguém puder me ajudar..

Um abraço a todos..

Daniel Simoes, RJ..
Avatar do usuário
fsitja
Rank: OraSauro
Rank: OraSauro
Mensagens: 611
Registrado em: Seg, 19 Jan 2009 4:29 pm
Localização: Gaúcho no Rio de Janeiro - RJ
"The scars exist to remind us that the past was real"
Campanha: Como fazer uma pergunta e obter uma resposta.
http://tkyte.blogspot.com/2005/06/how-t ... tions.html

OCA & OCP Developer — OCE SQL Expert — OCS Data Warehousing Specialist

Só exibindo um pouco do código... senão não tem como saber como está implementado o programa que gera esse texto.

Daria para postá-lo aqui por favor?
danielsimbra
Rank: Estagiário Pleno
Rank: Estagiário Pleno
Mensagens: 7
Registrado em: Qui, 18 Nov 2010 10:12 am
Localização: Rio de Janeiro

Esse é o trecho que eu estava tentando modificar..

Selecionar tudo

  IF MOD(LENGTH(vTEHISTLANC)/45,1) = 0
   THEN vLOOPHISTORICO := TRUNC(LENGTH(vTEHISTLANC)/45);
   ELSE vLOOPHISTORICO := TRUNC(LENGTH(vTEHISTLANC)/45)+1;
  END IF;
  vINDICE := 0;
  WHILE vINDICE < vLOOPHISTORICO LOOP
    vNULINHA := vNULINHA + 1;
    vINDICE  := vINDICE  + 1;
    IF vINDICE = 1 THEN
    vCARACTERINICIO := vINDICE;
    ELSE
    vCARACTERINICIO := vCARACTERINICIO + 45;
    END IF;
    IF vINDICE <> vLOOPHISTORICO THEN
    vVLLANCAUX :=0;
    ELSE
    vVLLANCAUX := vVLLANC;
    END IF; 
Mas não funciona..

Então eu fiz a seguinte rotina pra testar:

Selecionar tudo

declare
  vTeste  Varchar2(1000);
  vSaida varchar2(1000);
  vPosChar number(10);
  vLoopCtrl number(10);
  vLoop number(10);
  vLastSpace number(10);
begin
  vTeste := 'Daniel Simoes';   
  vPosChar := 1;
  vLoopCtrl := 1;
  vLoop := length(vTeste);
  vLastSpace := 0;
  -- Varre toda a linha
  while (vLoopCtrl <= vLoop) loop
    -- Armazerna a posição do último espaço
    if substr(vTeste,vPosChar,1) = ' ' then
      vLastSpace := vPosChar;
    end if; 
   
    -- Verifica se pode fazer a quebra de linha
    if (vPosChar = 10) and (vPosChar < vLoop) then
      -- Testa para ver se o próximo caractere  
      -- faz parte da palavra
      if substr(vTeste,vPosChar+1,1) <> ' ' then
        -- Copia todo o conteudo até a última palavra válida    
        vSaida := substr(vSaida,1,vLastSpace);   
        dbms_output.put_line('Trecho Quebra: ' || vSaida);
        -- Copia o trecho restante
        vTeste := Substr(vTeste,vPosChar,Length(vTeste));       
        vSaida := '';
        vPosChar := 1;
        vLastSpace := 0;
       
      end if;  
    end if;
    vSaida := vSaida || substr(vTeste,vPosChar,1);
     
    vPosChar := vPosChar + 1;
    vLoopCtrl := vLoopCtrl + 1;
  end loop;
  dbms_output.put_line('Trecho Final: ' || vSaida);
end; 
Mas mesmo assim ainda não está satisfatório...
Avatar do usuário
fsitja
Rank: OraSauro
Rank: OraSauro
Mensagens: 611
Registrado em: Seg, 19 Jan 2009 4:29 pm
Localização: Gaúcho no Rio de Janeiro - RJ
"The scars exist to remind us that the past was real"
Campanha: Como fazer uma pergunta e obter uma resposta.
http://tkyte.blogspot.com/2005/06/how-t ... tions.html

OCA & OCP Developer — OCE SQL Expert — OCS Data Warehousing Specialist

Acho que dá para fazer algo assim:

Selecionar tudo

SQL> set serveroutput on
SQL> 
SQL> DECLARE
  2    v_teste       VARCHAR2(4000) := 'Daniel Simoes foi ao mercado comprar pão e leite.';
  3    v_limite      NUMBER := 10;
  4    v_saida       VARCHAR2(4000);
  5    v_resto       VARCHAR2(4000);
  6    v_prox_trecho VARCHAR2(4000);
  7    v_linha       NUMBER := 0;
  8  BEGIN
  9    v_resto := v_teste;
 10    LOOP
 11      v_prox_trecho := regexp_substr(v_resto, '^[^ ]+\s*');
 12      -- se for menor do que o tamanho máximo da linha
 13      IF (nvl(length(rtrim(v_prox_trecho)), 0) + nvl(length(v_saida), 0) <= v_limite)
 14         AND v_prox_trecho IS NOT NULL
 15      THEN
 16        v_resto := regexp_replace(v_resto, '^[^ ]+\s*');
 17        v_saida := ltrim(v_saida || ' ') || rtrim(v_prox_trecho);
 18      ELSE
 19        v_linha := v_linha + 1;
 20        dbms_output.put_line(v_linha || ' - ' || v_saida);
 21        v_saida := rtrim(v_prox_trecho);
 22        v_resto := regexp_replace(v_resto, '^[^ ]+\s*');
 23        EXIT WHEN v_resto IS NULL;
 24      END IF;
 25    END LOOP;
 26  END;
 27  /
 
1 - Daniel
2 - Simoes foi
3 - ao mercado
4 - comprar pão
5 - e leite.
 
PL/SQL procedure successfully completed
 
SQL> 
Tem que testar melhor para ver se não tem algum bug de repente.

Falou!
Avatar do usuário
fsitja
Rank: OraSauro
Rank: OraSauro
Mensagens: 611
Registrado em: Seg, 19 Jan 2009 4:29 pm
Localização: Gaúcho no Rio de Janeiro - RJ
"The scars exist to remind us that the past was real"
Campanha: Como fazer uma pergunta e obter uma resposta.
http://tkyte.blogspot.com/2005/06/how-t ... tions.html

OCA & OCP Developer — OCE SQL Expert — OCS Data Warehousing Specialist

Achei um bug já... estava verificando errado no if:

Selecionar tudo

SQL> set serveroutput on
SQL> DECLARE
  2    v_teste       VARCHAR2(4000) := 'Daniel Simoes foi ao mercado comprar pão e leite.';
  3    v_limite      NUMBER := 10;
  4    v_saida       VARCHAR2(4000);
  5    v_resto       VARCHAR2(4000);
  6    v_prox_trecho VARCHAR2(4000);
  7    v_linha       NUMBER := 0;
  8  BEGIN
  9    v_resto := v_teste;
 10    LOOP
 11      v_prox_trecho := regexp_substr(v_resto, '^[^ ]+\s*');
 12      -- se for menor do que o tamanho máximo da linha
 13      IF (length(ltrim(v_saida || ' ') || rtrim(v_prox_trecho)) <= v_limite)
 14         AND v_prox_trecho IS NOT NULL
 15      THEN
 16        v_resto := regexp_replace(v_resto, '^[^ ]+\s*');
 17        v_saida := ltrim(v_saida || ' ') || rtrim(v_prox_trecho);
 18      ELSE
 19        v_linha := v_linha + 1;
 20        dbms_output.put_line(v_linha || ' - ' || v_saida);
 21        v_saida := rtrim(v_prox_trecho);
 22        v_resto := regexp_replace(v_resto, '^[^ ]+\s*');
 23        EXIT WHEN v_saida IS NULL;
 24      END IF;
 25    END LOOP;
 26  END;
 27  /
 
1 - Daniel
2 - Simoes foi
3 - ao mercado
4 - comprar
5 - pão e
6 - leite.
 
PL/SQL procedure successfully completed
danielsimbra
Rank: Estagiário Pleno
Rank: Estagiário Pleno
Mensagens: 7
Registrado em: Qui, 18 Nov 2010 10:12 am
Localização: Rio de Janeiro

Ok!!

Vou verificar aqui e posto o resultado neste tópico..

Obrigado!!
danielsimbra
Rank: Estagiário Pleno
Rank: Estagiário Pleno
Mensagens: 7
Registrado em: Qui, 18 Nov 2010 10:12 am
Localização: Rio de Janeiro

Botei pra executar essa rotina mas deu o seguinte erro:

Relatório de erro:
ORA-06550: linha 11, coluna 24:
PLS-00201: o identificador 'REGEXP_SUBSTR' deve ser declarado
ORA-06550: linha 11, coluna 7:
PL/SQL: Statement ignored
ORA-06550: linha 16, coluna 20:
PLS-00201: o identificador 'REGEXP_REPLACE' deve ser declarado
ORA-06550: linha 16, coluna 9:
PL/SQL: Statement ignored
ORA-06550: linha 22, coluna 20:
PLS-00201: o identificador 'REGEXP_REPLACE' deve ser declarado
ORA-06550: linha 22, coluna 9:
PL/SQL: Statement ignored
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:

Usei o SQL Developer..

Minha versão do oracle é a 10g, o que tem de errado??

att,
Daniel, RJ.
paulochagas
Moderador
Moderador
Mensagens: 86
Registrado em: Qua, 15 Mar 2006 2:46 pm
Localização: São Paulo - SP
Paulo Chagas Filho
__________________

Analista Funcional / Desenvolvedor Oracle EBS
MSN - paulochagas@hotmail.com
Gtalk - pachafi@gmail.com
Skype - paulochagas

Creio que Funções com Expressões regulares só funcionam em versões do Oracle 10G ou mais recente
Avatar do usuário
fsitja
Rank: OraSauro
Rank: OraSauro
Mensagens: 611
Registrado em: Seg, 19 Jan 2009 4:29 pm
Localização: Gaúcho no Rio de Janeiro - RJ
"The scars exist to remind us that the past was real"
Campanha: Como fazer uma pergunta e obter uma resposta.
http://tkyte.blogspot.com/2005/06/how-t ... tions.html

OCA & OCP Developer — OCE SQL Expert — OCS Data Warehousing Specialist

Deve ser isso mesmo... seu Oracle é 9i?

Aí vai ter que fazer ums ginástica maior com instr() e substr(), procurando espaços.
danielsimbra
Rank: Estagiário Pleno
Rank: Estagiário Pleno
Mensagens: 7
Registrado em: Qui, 18 Nov 2010 10:12 am
Localização: Rio de Janeiro

Galera, obrigado pelas dicas..

Consegui resolver o problema..

Mas tive problemas em executar o código que vocês me passaram justamente pelo fato do meu oracle ser o 9i.. :(

Então, dei uma estudada nos dois códigos (meu e de vocês) e verifiquei melhor, concluí que tinha alguns bugs pra resolverem que consegui corrigir no código abaixo:

Selecionar tudo

set serveroutput on
declare
  vTeste  Varchar2(1000);
  vSaida varchar2(1000);
  vPosChar number(10);
  vLoopCtrl number(10);
  vLoop number(10);
  vLastSpace number(10);
  vPosNova number(10); -- NOVO
begin
  vTeste     := 'Daniel Simoes foi ao mercado comprar coisas';   
  vPosChar   := 1;
  vLoopCtrl  := 1;
  vLoop      := length(vTeste);
  vLastSpace := 0;
  vPosNova   := 0; -- NOVO
  -- Varre toda a linha
  while (vLoopCtrl <= vLoop) loop
    -- Armazerna a posição do último espaço
    if substr(vTeste,vPosChar,1) = ' ' then
      vLastSpace := vPosChar;
    end if; 
   
    -- Verifica se pode fazer a quebra de linha
    if (vPosChar = 10) and (vPosChar < vLoop) then
      -- Testa para ver se o próximo caractere  
      -- faz parte da palavra
      if substr(vTeste,vPosChar+1,1) <> ' ' then
        -- Copia todo o conteudo até a última palavra válida    
        vSaida := substr(vSaida,1,vLastSpace);   
        dbms_output.put_line('Trecho Quebra: ' || vSaida);
        vPosNova := vLastSpace; -- NOVO
        -- Copia o trecho restante
        vTeste     := Substr(vTeste,vPosNova,Length(vTeste));       
        vSaida     := '';
        vPosChar   := 1;
        vLastSpace := 0;
        vPosNova   := 0; -- NOVO
        vLoopCtrl  := 0; -- NOVO
      end if;  
    end if;
    vSaida    := vSaida || substr(vTeste,vPosChar,1);
    vPosChar  := vPosChar + 1;
    vLoopCtrl := vLoopCtrl + 1;
  end loop;
  dbms_output.put_line('Trecho Final: ' || vSaida);
end;
Funcionou dessa forma:

1 Daniel
2 Simoes
3 foi ao
4 mercado
5 comprar
6 coisas

ps.: O que eu comentei como "NOVO" ao final da linha de código, são as alterações que fiz pra rotina funcionar...

Muito obrigado a todos pela ajuda... :D

Abraços!!!

att,
Daniel Simões, RJ..
LaraJacuniak
Rank: Estagiário Júnior
Rank: Estagiário Júnior
Mensagens: 1
Registrado em: Sex, 19 Nov 2010 9:45 am
Localização: Curitiba

Olá pessoal,

Utilizo o forum de faz bastante tempo, e já me ajudou muito!

Para a pergunta do colega acima, tem uma solução um pouco mais simples.
Fico feliz por poder ajudar um pouco!

abraços!!

Selecionar tudo

SELECT Trim(SUBSTR('Daniel Simoes agora faz em uma linha somente',INSTR('Daniel Simoes agora faz em uma linha somente',' ',-1,1)))
  FROM dual;
:-o
Avatar do usuário
fsitja
Rank: OraSauro
Rank: OraSauro
Mensagens: 611
Registrado em: Seg, 19 Jan 2009 4:29 pm
Localização: Gaúcho no Rio de Janeiro - RJ
"The scars exist to remind us that the past was real"
Campanha: Como fazer uma pergunta e obter uma resposta.
http://tkyte.blogspot.com/2005/06/how-t ... tions.html

OCA & OCP Developer — OCE SQL Expert — OCS Data Warehousing Specialist

Olá LaraJacuniak,

Bem-vindo ao fórum como colaborador também 8)

A dificuldade que o Daniel estava enfrentando era "formatar" a entrada, quebrando em linhas por um limite de largura de linha determinado.

Nesse sentido, fica um pouco mais complexo de resolver em SQL apenas. Creio que precisaria usar Connect By, With-Recursivo ou Model, mas sem expressões regulares é preferível resolvr com PL/SQL mesmo, pela complexidade excessiva do SQL.
burga
Rank: DBA Pleno
Rank: DBA Pleno
Mensagens: 232
Registrado em: Qui, 26 Nov 2009 1:05 pm
Localização: SP
Ricardo H. Tajiri

Com a cláusula MODEL ficaria:

Selecionar tudo

SELECT text2
  FROM dual
 MODEL DIMENSION BY (1 AS x)
 MEASURES ('Teste de sttring com quebra de linha a cada 45 caracteres, onde não se deve quebrar a linha no meio de uma palavra. Esta deve ser a mensagem que será quebrada e na cláusula MEASURES variavel tamanho é onde se deve alterar pro tamanho máximo desejado de cada linha...' as text, 
 0 AS i1, 1 AS i2, CAST(NULL AS VARCHAR2(4000))  AS text2, 45 AS tamanho)
 RULES ITERATE (500)  UNTIL (i1[1]+tamanho[1] >= LENGTH(text[1]))
 (  i1[1] = i1[1] + i2[1],
    i2[1] = INSTR(SUBSTR(text[1], i1[1],tamanho[1]),' ',-1),
 text2[1] = NVL2(text2[1],text2[1] || CHR(10),'') || CASE WHEN LENGTH(SUBSTR(text[1], i1[1])) <= tamanho[1] THEN SUBSTR(text[1], i1[1]) ELSE SUBSTR(text[1], i1[1],i2[1]) END); 
Com a saída:

Selecionar tudo

TEXT2                                       
--------------------------------------------
Teste de sttring com quebra de linha a cada 
45 caracteres, onde não se deve quebrar a   
linha no meio de uma palavra. Esta deve ser 
a mensagem que será quebrada e na cláusula  
MEASURES variavel tamanho é onde se deve    
alterar pro tamanho máximo desejado de cada 
linha...
Avatar do usuário
fsitja
Rank: OraSauro
Rank: OraSauro
Mensagens: 611
Registrado em: Seg, 19 Jan 2009 4:29 pm
Localização: Gaúcho no Rio de Janeiro - RJ
"The scars exist to remind us that the past was real"
Campanha: Como fazer uma pergunta e obter uma resposta.
http://tkyte.blogspot.com/2005/06/how-t ... tions.html

OCA & OCP Developer — OCE SQL Expert — OCS Data Warehousing Specialist

Nossa, muito bom, o Burga se inspirou :-o

Tomando a liberdade de usar sua solução Burga, eu tinha pensado em algo assim:

Selecionar tudo

SQL> with tab_texto as (
  2  select 'Teste de sttring com quebra de linha a cada 45 caracteres, onde não se deve quebrar a linha no meio de uma palavra. Esta deve ser a mensagem que será quebrada e na cláusula MEASURES variavel tamanho é onde se deve alterar pro tamanho máximo desejado de cada linha...' as text from dual)
  3  -- fim dados de exemplo
  4  SELECT x as num_linha, linha
  5    FROM (select text, rownum as x from tab_texto)
  6   MODEL DIMENSION BY (x)
  7   MEASURES (text,
  8   0 AS i1, 1 AS i2, CAST(NULL AS VARCHAR2(4000))  AS text2, 45 AS tamanho, cast(null as varchar2(4000)) as linha)
  9   RULES ITERATE (500)  UNTIL (i1[1]+tamanho[1] >= LENGTH(text[1]))
 10   (  i1[1] = i1[1] + i2[1],
 11      i2[1] = INSTR(SUBSTR(text[1], i1[1],tamanho[1]),' ',-1),
 12   text2[iteration_number+1] = NVL2(text2[1],text2[1] || CHR(10),'') || CASE WHEN LENGTH(SUBSTR(text[1], i1[1])) <= tamanho[1]
 13                                                            THEN SUBSTR(text[1], i1[1])
 14                                                            ELSE SUBSTR(text[1], i1[1],i2[1]) END,
 15   linha[iteration_number+1] =CASE WHEN LENGTH(SUBSTR(text[1], i1[1])) <= tamanho[1]
 16                                   THEN SUBSTR(text[1], i1[1])
 17                                   ELSE SUBSTR(text[1], i1[1],i2[1]) END
 18   );
 
 NUM_LINHA LINHA
---------- --------------------------------------------------------------------------------
         1 Teste de sttring com quebra de linha a cada
         2 45 caracteres, onde não se deve quebrar a
         3 linha no meio de uma palavra. Esta deve ser
         4 a mensagem que será quebrada e na cláusula
         5 MEASURES variavel tamanho é onde se deve
         6 alterar pro tamanho máximo desejado de cada
         7 linha...
 
7 rows selected
Porém, seria utilizando uma tabela com vários textos, no estilo:

Selecionar tudo

with tab_texto as (
select 'Teste de sttring com quebra de linha a cada 45 caracteres, onde não se deve quebrar a linha no meio de uma palavra. Esta deve ser a mensagem que será quebrada e na cláusula MEASURES variavel tamanho é onde se deve alterar pro tamanho máximo desejado de cada linha...' as text from dual union all
select 'texto 2 com mais linhas e por aí vai...' from dual)
Fazendo para N linhas na tabela de origem o buraco fica mais embaixo... teria que fazer um Model multidimensional talvez? Ou misturar query hierárquica com a saída do model?

Sexta-feira, hora do rush... vou deixar pra segunda essa brincadeira.
:lol:
burga
Rank: DBA Pleno
Rank: DBA Pleno
Mensagens: 232
Registrado em: Qui, 26 Nov 2009 1:05 pm
Localização: SP
Ricardo H. Tajiri

E aí fsitja... Ótima solução também,

Quebrando em linhas "reais" fica mais facil de visualizar o resultado. Uma coisa que eu não me atentei é no caso de já existir uma quebra de linha no meio do texto. Algumas linhas no resultado final seriam afetadas com essa quebra...

Fiquei curioso quanto ao desafio de fazer pra várias linhas da tabela de origem. A solução que encontrei foi particionar por linha, pros textos serem tratados de forma independente. Deu certo!!! :-o

Olha aí o bichão com as correções e particionando por textos:

Selecionar tudo

WITH tab_texto AS (
  SELECT 'Teste de sttring com quebra de linha a cada 45 caracteres, onde não se deve quebrar a linha no meio de uma palavra. 
Esta deve ser a mensagem que será quebrada e na cláusula MEASURES variavel tamanho é onde se deve alterar pro tamanho máximo desejado de cada linha...' AS text FROM dual
  UNION ALL
  SELECT 'Teste de string 2 com mais de uma linha na tabela origem.
YEAH-YEAH, pegadinha do malandro!!' AS text FROM dual
  UNION ALL
  SELECT 'Teste de string 3... Será que vai dar certo???' AS text FROM dual
)
  SELECT y AS num_texto, x AS num_linha, linha
    FROM (SELECT text, ROWNUM AS y FROM tab_texto)
   MODEL 
   PARTITION BY (y)
   DIMENSION BY (1 as x)
   MEASURES (text, length(text) tamanho2,
   0 AS i1, 1 AS i2, CAST(NULL AS VARCHAR2(4000))  AS text2, 45 AS tamanho, CAST(NULL AS VARCHAR2(4000)) as linha)
   RULES ITERATE (500)  UNTIL (i1[1]+tamanho[1] > tamanho2[1])
   (  i1[1] = i1[1] + i2[1],
      i2[1] = DECODE(INSTR(SUBSTR(text[1], i1[1],tamanho[1]),CHR(10)),0,INSTR(SUBSTR(text[1], i1[1],tamanho[1]),' ',-1),INSTR(SUBSTR(text[1], i1[1],tamanho[1]),CHR(10))),
   text2[1] = NVL2(text2[1],text2[1] || CHR(10),'') || CASE WHEN LENGTH(SUBSTR(text[1], i1[1])) <= tamanho[1]
                                                            THEN REPLACE(SUBSTR(text[1], i1[1]),CHR(10))
                                                            ELSE REPLACE(SUBSTR(text[1], i1[1],i2[1]),CHR(10)) END,
   linha[iteration_number+1] =CASE WHEN LENGTH(SUBSTR(text[1], i1[1])) <= tamanho[1]
                                   THEN REPLACE(SUBSTR(text[1], i1[1]),CHR(10))
                                   ELSE REPLACE(SUBSTR(text[1], i1[1],i2[1]),CHR(10)) END
   )
   ORDER BY 1, 2;
Resultado:

Selecionar tudo

NUM_TEXTO              NUM_LINHA              LINHA                                  
---------------------- ---------------------- ---------------------------------------------
1                      1                      Teste de sttring com quebra de linha a cada  
1                      2                      45 caracteres, onde não se deve quebrar a    
1                      3                      linha no meio de uma palavra.                
1                      4                      Esta deve ser a mensagem que será quebrada e 
1                      5                      na cláusula MEASURES variavel tamanho é onde 
1                      6                      se deve alterar pro tamanho máximo desejado  
1                      7                      de cada linha...                             
2                      1                      Teste de string 2 com mais de uma linha na   
2                      2                      tabela origem.                               
2                      3                      YEAH-YEAH, pegadinha do malandro!!           
3                      1                      Teste de string 3... Será que vai dar        
3                      2                      certo???                                     

12 linhas selecionadas
Mas ainda não tenho certeza se a condição da cláusula UNTIL está correta, falta fazer mais testes...

Se misturar consulta hierárquica com MODEL e der certo deve ficar bizarro o código, não consigo nem imaginar uma forma de fazer assim... 8)

Vou esperar pra ver se alguém aí se dispõe a arriscar... :lol:
danielsimbra
Rank: Estagiário Pleno
Rank: Estagiário Pleno
Mensagens: 7
Registrado em: Qui, 18 Nov 2010 10:12 am
Localização: Rio de Janeiro

Semana passada, eu havia postado aqui as alterações que fiz no código que apresentei nesse tópico com relação ao problema que eu estava tendo e funcionou..

O maior problema, por incrível que pareça, está sendo quando justamente a posição de quebra de linha é um espaço em branco.

A rotina está quebrando normalmente, mas ela está pegando a última letra da última palavra antes deste espaço, e está quebrando a linha de forma meio desfigurada..

Ex.: Daniel foi[ESPAÇO]a feira, em vez de ficar assim:

Daniel foi
a feira

Está ficando assim:

Daniel foi
i a feira

Alguém tem alguma idéia??
danielsimbra
Rank: Estagiário Pleno
Rank: Estagiário Pleno
Mensagens: 7
Registrado em: Qui, 18 Nov 2010 10:12 am
Localização: Rio de Janeiro

O código que eu havia postado, foi esse abaixo:

Selecionar tudo

set serveroutput on
declare
  vTeste  Varchar2(1000);
  vSaida varchar2(1000);
  vPosChar number(10);
  vLoopCtrl number(10);
  vLoop number(10);
  vLastSpace number(10);
  vPosNova number(10); -- NOVO
begin
  vTeste     := 'Daniel Simoes foi ao mercado comprar coisas';   
  vPosChar   := 1;
  vLoopCtrl  := 1;
  vLoop      := length(vTeste);
  vLastSpace := 0;
  vPosNova   := 0; -- NOVO
  -- Varre toda a linha
  while (vLoopCtrl <= vLoop) loop
    -- Armazerna a posição do último espaço
    if substr(vTeste,vPosChar,1) = ' ' then
      vLastSpace := vPosChar;
    end if;
   
    -- Verifica se pode fazer a quebra de linha
    if (vPosChar = 10) and (vPosChar < vLoop) then
      -- Testa para ver se o próximo caractere 
      -- faz parte da palavra
      if substr(vTeste,vPosChar+1,1) <> ' ' then
        -- Copia todo o conteudo até a última palavra válida   
        vSaida := substr(vSaida,1,vLastSpace);   
        dbms_output.put_line('Trecho Quebra: ' || vSaida);
        vPosNova := vLastSpace; -- NOVO
        -- Copia o trecho restante
        vTeste     := Substr(vTeste,vPosNova,Length(vTeste));       
        vSaida     := '';
        vPosChar   := 1;
        vLastSpace := 0;
        vPosNova   := 0; -- NOVO
        vLoopCtrl  := 0; -- NOVO
      end if; 
    end if;
    vSaida    := vSaida || substr(vTeste,vPosChar,1);
    vPosChar  := vPosChar + 1;
    vLoopCtrl := vLoopCtrl + 1;
  end loop;
  dbms_output.put_line('Trecho Final: ' || vSaida);
end; 
burga
Rank: DBA Pleno
Rank: DBA Pleno
Mensagens: 232
Registrado em: Qui, 26 Nov 2009 1:05 pm
Localização: SP
Ricardo H. Tajiri

Se você precisa disso dentro de um bloco em PL/SQL, pode utilizar as consultas que já apresentamos aqui:

Selecionar tudo

set serveroutput on 
BEGIN

  FOR i IN (
    WITH tab_texto AS (
      SELECT 'Teste de sttring com quebra de linha a cada 45 caracteres, onde não se deve quebrar a linha no meio de uma palavra. Esta deve ser a mensagem que será quebrada e na cláusula MEASURES variavel tamanho é onde se deve alterar pro tamanho máximo desejado de cada linha...' AS text FROM dual
    )
      SELECT y AS num_texto, x AS num_linha, linha
        FROM (SELECT text, ROWNUM AS y FROM tab_texto)
       MODEL
       PARTITION BY (y)
       DIMENSION BY (1 as x)
       MEASURES (text, length(text) tamanho2,
       0 AS i1, 1 AS i2, CAST(NULL AS VARCHAR2(4000))  AS text2, 45 AS tamanho, CAST(NULL AS VARCHAR2(4000)) as linha)
       RULES ITERATE (500)  UNTIL (i1[1]+tamanho[1] > tamanho2[1])
       (  i1[1] = i1[1] + i2[1],
          i2[1] = DECODE(INSTR(SUBSTR(text[1], i1[1],tamanho[1]),CHR(10)),0,INSTR(SUBSTR(text[1], i1[1],tamanho[1]),' ',-1),INSTR(SUBSTR(text[1], i1[1],tamanho[1]),CHR(10))),
       text2[1] = NVL2(text2[1],text2[1] || CHR(10),'') || CASE WHEN LENGTH(SUBSTR(text[1], i1[1])) <= tamanho[1]
                                                                THEN REPLACE(SUBSTR(text[1], i1[1]),CHR(10))
                                                                ELSE REPLACE(SUBSTR(text[1], i1[1],i2[1]),CHR(10)) END,
       linha[iteration_number+1] =CASE WHEN LENGTH(SUBSTR(text[1], i1[1])) <= tamanho[1]
                                       THEN REPLACE(SUBSTR(text[1], i1[1]),CHR(10))
                                       ELSE REPLACE(SUBSTR(text[1], i1[1],i2[1]),CHR(10)) END
       )
       ORDER BY 1, 2) 
  LOOP
    DBMS_OUTPUT.PUT_LINE(LPAD(i.num_linha,4,'0') || ':  ' || i.linha);
 END LOOP;

END;
Responder
  • Informação
  • Quem está online

    Usuários navegando neste fórum: Nenhum usuário registrado e 4 visitantes