Страница 1 из 1

Работа с длинными строками.

СообщениеДобавлено: 16 ноя 2008 14:42
tvrsh
Максимальная длинна одного PRIVMSG сообщения ограничивается возможностями ircd и вашим клиентом. Обычно размер составляет 512 байт. Часть сообщения составляют "служебные" данные, оговоренные irc протоколом, и чтобы определить фактический размер сообщения надо из общего размера удалить эту протокольную часть.
(:bot!user@host PRIVMSG target :\r\n)

Вот процедура которая подгоняет длинные сообщения под необходимый размер и отсылает их по частям.
TCL: [ Скачать ] [ Скрыть ]
proc msg {dest data} {
   set len [expr {512-[string len ":$::botname PRIVMSG $dest :\r\n"]}]
   foreach line [wordwrap $data $len] {
      puthelp "PRIVMSG $dest :$line"
   }
}
# Процедура wordwrap proc получающая строку и необходимый размер
# (пустые строки будут удаляться так как передать их нет возможности)
proc wordwrap {data len} {
   set out {}
   foreach line [split [string trim $data] \n] {
      set curr {}
      set i 0
      foreach word [split [string trim $line]] {
         if {[incr i [string len $word]]>$len} {
            lappend out [join $curr]
            set curr [list $word]
            set i [string len $word]
         } {
            lappend curr $word
         }
         incr i
      }
      if {[llength $curr]} {
         lappend out [join $curr]
      }
   }
   set out
}


(Для работы этой процедуры необходимо, чтобы $botname содержала в себе маску вашего бота, что не всегда возможно в сетях скрывающих реальные хосты - если вы находитесь в такой сети вам придется указывать размер переменной $::botname напрямую)

Вольный перевод поста с egghelp.org

Re: Работа с длинными строками.

СообщениеДобавлено: 16 ноя 2008 16:35
tvrsh
Еще один вариант:

TCL: [ Скачать ] [ Скрыть ]
# Получаем того, кому отсылать текст, сам текст, длинну строк и символы
# по которым разбиваем строку.
proc largetext {target text {lineLen 400} {delims {;:.,-!}}} {
      if {[string length $text] <= $lineLen} {
         putserv "PRIVMSG $target :$text"
         return
     }
  set _text [split $text $delims]
  set x 0; set i 0
  while {$x < $lineLen} {
    if {$i >= [llength $_text]} { return }
    set wordlen [string length [lindex $_text $i]];
      if {$x + $wordlen > $lineLen} { break }
      incr x $wordlen
      incr x; incr i
      }
putserv "PRIVMSG $target :[string range $text 0 [expr $x - 1]] "
largetext $target [string trimleft [string range $text $x end]] $lineLen $delims
}

Re: Работа с длинными строками.

СообщениеДобавлено: 06 янв 2010 15:12
tvrsh
И еще одна реализация. Процедура разбивает передаваемый в нее текст на отрезки по 400 байт. Взято из библиотеки fsck.tcl.

TCL: [ Скачать ] [ Скрыть ]
# splitmsg:
#  Splits a message into 400byte chunks.
#  Some messages exceed the 512 byte buffer of most ircds,
#  so here's the solution, this function splits each message
#  into a list with 400byte chunks (400+channelname+userhost etc).
#  The message will not be split in words, only between them.
proc splitmsg {string} {
  set buf1 ""; set buf2 [list];
  foreach word [split $string] {
    append buf1 " " $word;
    if {[string length $buf1]-1 >= 400} {
      lappend buf2 [string range $buf1 1 end];
      set buf1 "";
    }
  }
  if {$buf1 != ""} {
    lappend buf2 [string range $buf1 1 end];
  }
  return $buf2;
}

Re: Работа с длинными строками.

СообщениеДобавлено: 29 дек 2013 00:07
tvrsh
И еще один вариант:

TCL: [ Скачать ] [ Скрыть ]
bind pub - !large largemsg
proc largemsg {nick uhost hand chan text} {

    set maxlength [expr 70 - [string bytelength ":$::botname PRIVMSG $chan :\r\n"]]

    if {[string bytelength $text] <= $maxlength} {
        putserv "PRIVMSG $chan :$text"    
        return 0
    } else {
        set splittext [split $text]        
        set newstring [list ]        
        set i 0
        foreach textelem $splittext {
            if {[string bytelength [join $newstring]] <= $maxlength} {
                lappend newstring $textelem
                incr i
            }
        }

        putserv "PRIVMSG $chan :[join [lrange $newstring 0 end-1]]"
        largemsg $nick $uhost $hand $chan [lrange $splittext [incr i -1] end]
    }
}


<tvrsh> !large qqq www eee rrr ttt yyy uuu iii ooo ppp aaa sss ddd fff ggg hhh jjj kkk lll
<+bionic> qqq www eee rrr ttt yyy
<+bionic> uuu iii ooo ppp aaa sss
<+bionic> ddd fff ggg hhh jjj kkk
<+bionic> lll


Обновил этот вариант. Заменил string length на string bytelength чтобы избежать проблем с текстом в утф. При использовании этого кода замените 70 на длину строки для вашего ircd. 70 сделано для проверки, чтобы передаваемый с канала текст разбить.

Re: Работа с длинными строками.

СообщениеДобавлено: 18 янв 2014 16:06
tvrsh
Объединил пример из предыдущего сообщения с Процедура получения последнего цвета в строке:

TCL: [ Скачать ] [ Скрыть ]
# Работа с длинными строками.
proc ::tutu::print {text chan} {
    variable tutu

    set maxlength [expr 512 - [string bytelength ":$::botname PRIVMSG $chan :\r\n"]]

    if {[string bytelength $text] <= $maxlength} {
        putserv "PRIVMSG $chan :$text"    
        return 0
    } else {
        set splittext [split $text]        
        set newstring [list ]        
        set i 0
        foreach textelem $splittext {
            if {[string bytelength [join $newstring]] <= $maxlength} {
                lappend newstring $textelem
                incr i
            }
        }
       
        putserv "PRIVMSG $chan :[join [lrange $newstring 0 end-1]]"
        set color [string range [lindex [split [join [lrange $newstring 0 end-1]] "\003"] [expr [llength [split [join [lrange $newstring 0 end-1]] "\003"]] - 1]] 0 1]
        ::tutu::print [expr {[isnumber $color] ? "\003$color" : ""}][expr {([regexp -all {\002} [join [lrange $newstring 0 end-1]]] & 1) == 0 ? "" : "\002"}][expr {([regexp -all {\037} [join [lrange $newstring 0 end-1]]] & 1) == 0 ? "" : "\037"}][join [lrange $splittext [incr i -1] end]] $chan
    }
}

Также добавил проверку на наличие болда в первой половине сообщения:
[expr {([regexp -all {\002} [join [lrange $newstring 0 end-1]]] & 1) == 0 ? "" : "\002"}]

Если в предыдущем отрезке сообщения нечетное количество идентификаторов \002, это значит, что последний из них не закрылся, и новая строка должна начаться с \002 для того, чтобы закрывающий болд сработал как надо. Если в начало строки не подставить \002, то болд, который должен закрыть предыдущий отрезок жирного текста, сработает как открывающий, и зажирнит не то что нужно.

Тоже самое и тут:
[expr {([regexp -all {\037} [join [lrange $newstring 0 end-1]]] & 1) == 0 ? "" : "\037"}]
но только с подчеркиванием.