Как я могу сгруппировать неизвестные (но повторяющиеся) слова для создания индекса? - PullRequest
3 голосов
/ 19 апреля 2020

Мне нужно создать скрипт, который индексирует книгу (текстовый файл), взяв любые слова, заключенные в угловые скобки (<>), и сделав из этого индексный файл. У меня есть два вопроса, которые, надеюсь, вы мне поможете!

Первый - как определить слова в тексте, заключенные в угловые скобки. Я нашел похожий вопрос, который задавался, но требовал слова в квадратных скобках, и пытался манипулировать их кодом, но получаю ошибку.

grep -on \\<.*> index.txt

Исходный код был таким же, но с квадратные скобки вместо угловых скобок, и теперь я получаю сообщение об ошибке:

line 5: .*: ambiguous redirect

На этот вопрос ответили

Мне также сейчас нужно принять мой индекс и переформатировать его следующим образом:

1:big
3:big
9:big
2:but
4:sun
6:sun
7:sun
8:sun

Into:

big: 1 3 9
but: 2
sun: 4 6 7 8

Я знаю, что могу перевернуть столбцы с помощью команды awk, например:

awk -F':' 'BEGIN{OFS=":";} {print $2,$1;}' index.txt

Но я не уверен, как сгруппировать одни и те же слова в одну строку.

Спасибо!

Ответы [ 5 ]

3 голосов
/ 19 апреля 2020

Не могли бы вы попробовать следующее (если вас не беспокоит порядок сортировки, если вам нужно отсортировать его, добавьте sort к следующему коду).

awk '
BEGIN{
  FS=":"
}
{
  name[$2]=($2 in name?name[$2] OFS:"")$1
}
END{
  for(key in name){
    print key": "name[key]
  }
}
' Input_file

Объяснение: Добавление подробного пояснения к приведенному выше коду.

awk '                                        ##Starting awk program from here.
BEGIN{                                       ##Starting BEGIN section from here.
  FS=":"                                     ##Setting field separator as : here.
}
{
  name[$2]=($2 in name?name[$2] OFS:"")$1      ##Creating array named name with index of $2 and value of $1 which is keep appending to its same index value.
}
END{                                         ##Starting END block of this code here.
  for(key in name){                          ##Traversing through name array here.
    print key": "name[key]                   ##Printing key colon and array name value with index key
  }
}
' Input_file                                 ##Mentioning Input_file name here.
2 голосов
/ 19 апреля 2020

Что-то вроде этого может быть тем, что вам нужно, он выводит номер абзаца, номер строки в абзаце и положение символа в строке для каждого вхождения каждого целевого слова:

$ cat book.txt
Wee, <sleeket>, cowran, tim’rous beastie,
O, what a panic’s in <thy> breastie!
Thou need na start <awa> sae hasty,
          Wi’ bickerin brattle!
I wad be laith to rin an’ chase <thee>
          Wi’ murd’ring pattle!

I’m <truly> sorry Man’s dominion
Has broken Nature’s social union,
An’ justifies that ill opinion,
          Which makes <thee> startle,
At me, <thy> poor, earth-born companion,
          An’ fellow-mortal!

.

$ cat tst.awk
BEGIN { RS=""; FS="\n"; OFS="\t" }
{
    for (lineNr=1; lineNr<=NF; lineNr++) {
        line = $lineNr
        idx = 1
        while ( match( substr(line,idx), /<[^<>]+>/ ) ) {
            word = substr(line,idx+RSTART,RLENGTH-2)
            locs[word] = (word in locs ? locs[word] OFS : "") NR ":" lineNr ":" idx + RSTART
            idx += (RSTART + RLENGTH)
        }
    }
}
END {
    for (word in locs) {
        print word, locs[word]
    }
}

.

$ awk -f tst.awk book.txt | sort
awa     1:3:21
sleeket 1:1:7
thee    1:5:34  2:4:24
thy     1:2:23  2:5:9
truly   2:1:6

Образец ввода предоставлен Рабб ie Ожоги

2 голосов
/ 19 апреля 2020

Если вы хотите извлечь несколько вхождений подстрок в угловые скобки с помощью GNU grep, вы можете рассмотреть решение на основе регулярных выражений PCRE, например

grep -oPn '<\K[^<>]+(?=>)' index.txt

Механизм PCRE активируется с помощью -P и шаблон соответствует:

  • < - открытая угловая скобка
  • \K - оператор сброса соответствия, который отбрасывает весь найденный текст
  • [^<>]+ - 1 или более (из-за квантификатора +) любых символов, кроме < и > (см. Выражение в скобках [^<>])
  • (?=>) - положительный прогноз который требует (но не потребляет) символ > непосредственно справа от текущего местоположения.
1 голос
/ 19 апреля 2020

GNU datamash - удобный инструмент для работы с группами столбчатых данных (плюс некоторые sed для преобразования вывода в правильный формат):

$ grep -oPn '<\K[^<>]+(?=>)' index.txt | datamash -st: -g2 collapse 1 | sed 's/:/: /; s/,/ /g'
big: 1 3 9
but: 2
sun: 4 6 7 8
1 голос
/ 19 апреля 2020

Для преобразования index.txt

1:big
3:big
9:big
2:but
4:sun
6:sun
7:sun
8:sun

в:

big: 1 3 9
but: 2
sun: 4 6 7 8

вы можете попробовать эту программу AWK:

awk -F: '{ if (entries[$2]) {entries[$2] = entries[$2] " " $1} else {entries[$2] = $2 ": " $1} }
  END { for (entry in entries) print entries[entry] }' index.txt | sort

Более короткая версия того же, предложенного RavinderSingh13:

awk -F: '{ 
  { entries[$2] = ($2 in entries ? entries[$2] " " $1 : $2 ": " $1 }
  END { for (entry in entries) print entries[entry] }' index.txt | sort
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...