Строки соединения текста с повторным началом

В масштабе всей системы это было бы очень безрассудно по точно причине, которую Вы подозреваете - она вызовет значительную поломку в сценариях запуска и системных утилитах, которые зависят от sh-compatible поведения. Как Ulrich говорит, намного более безопасная альтернатива должна упаковать chroot в ящики или просто установить оболочку по умолчанию всех новых пользователей к/bin/ksh, хотя это не может сделать точно, что Вы хотите.

7
01.04.2015, 11:42
6 ответов

Это стандартная процедура для awk

awk '
{
  k=$2
  for (i=3;i<=NF;i++)
    k=k " " $i
  if (! a[$1])
    a[$1]=k
  else
    a[$1]=a[$1] "<br>" k
}
END{
  for (i in a)
    print i "\t" a[i]
}' long.text.file

Если файл отсортирован по первому слову в строке, то скрипт может быть более простым

awk '
{
  if($1==k)
    printf("%s","<br>")
  else {
    if(NR!=1)
      print ""
    printf("%s\t",$1)
  }
  for(i=2;i<NF;i++)
    printf("%s ",$i)
  printf("%s",$NF)
  k=$1
}
END{
print ""
}' long.text.file

или просто bash

unset n
while read -r word definition
do
    if [ "$last" = "$word" ]
    then
        printf "<br>%s" "$definition"
    else 
        if [ "$n" ]
        then
            echo
        else
            n=1
        fi
        printf "%s\t%s" "$word" "$definition"
        last="$word"
     fi
done < long.text.file
echo
3
27.01.2020, 20:16

Попробуйте

awk 'BEGIN { before="" } 
{ if ( $1 == before ) { $1="" ; printf "<br>%s",$0 ; } 
  else { printf "\n%s",$0 ;} ; before=$1 ; } 
END { printf "\n"  ;}'

, которые дают с вашим входом

word1  some text<br> some other text
word2  more text
word3  even more

Tha awk в основном запомните первое слово на предыдущей строке и не печатайте новую строку.

-1
27.01.2020, 20:16

Это действительно стандартный для awk . Вот краткий раствор, который не меняет операционные данные:

awk 'BEGIN { FS="\t" }
     $1!=key { if (key!="") print out ; key=$1 ; out=$0 ; next }
     { out=out"<br>"$2 }
     END { print out }'
2
27.01.2020, 20:16

В Python:

import sys

def join(file_name, join_text):
    prefix = None
    current_line = ''
    for line in open(file_name):
        if line and line[-1] == '\n':
            line = line[:-1]
        try:
            first_word, rest = line.split('\t', 1)
        except:
            first_word = None  # empty line or one without tab
            rest = line
        if first_word == prefix:
            current_line += join_text + rest
        else:
            if current_line:
                print current_line
            current_line = line
            prefix = first_word

    if current_line:  # do the last line(s)
        print current_line


join(sys.argv[2], sys.argv[1])

Это ожидает сепаратор (
) в качестве первого аргумента для программы и имени файла в качестве второго аргумента

1
27.01.2020, 20:16
perl -p0E 'while(s/^((.+?)\t.*)\n\2\t/$1<br>/gm){}' 

(Нужно 2 секунды, чтобы обработать словарь 23MB, 1.5Mlines, в моем 6-ти летнем ноутбуке)

3
27.01.2020, 20:16

С sed :

sed '$!N;/^\([^\t]*\t\)\(.*\)\(\n\)\1/!P;s//\3\1\2<br>/;D' <<\IN
word1  some text
word1  some other text
word1  some other other text
word2  more text
word3  even more
word3  and still more
IN

(примечание: для многих sed s вышеупомянутый переход \ t недопустим и буквальный ) Вместо него следует использовать символ )

И если у вас есть GNU sed , вы можете написать его немного проще:

sed -E '$!N;/^(\S+\t)(.*)\n\1/!P;s//\n\1\2<br>/;D' <infile

Он работает, постепенно складывая ввод по мере чтения. Если две последовательные строки не начинаются с одной и той же непробельной строки, тогда первая из них будет P ритирована. В противном случае промежуточная новая строка перемещается в начало строки, а соответствующая строка, следующая сразу за ней (чтобы включить табуляцию) , заменяется строкой
.

Обратите внимание, что используемый здесь метод стекирования может иметь последствия для производительности, если строка, которую собирает sed , становится очень длинной. Если его размер превышает 8 КБ, он превысит минимальный размер буфера пространства шаблона, указанный в POSIX.

Независимо от того, какая из двух возможностей возникла, последней sed D выбирается до первого встречающегося \ n символа ewline в пространстве шаблонов и начинается с того, что останки. И поэтому, когда две последовательные строки не начинаются с идентичных строк, первая печатается и удаляется, в противном случае выполняется подстановка, и D elete удаляет только \ n ewline, который ранее был разделен их.

Итак, приведенная выше команда напечатает:

word1  some text<br>some other text<br>some other other text
word2  more text
word3  even more<br>and still more

Я использовал << \ HERE_DOC для ввода выше, но вам, вероятно, следует отбросить все из << \ IN и использовать вместо этого.

3
27.01.2020, 20:16

Теги

Похожие вопросы