как разбить строку в первом символе точки на основе количества слов и повторить процесс в результирующих строках (в пространстве образца) - PullRequest
1 голос
/ 09 октября 2019

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

Пример входных данных:

1I got from Dr. Smith, the OK to keep working.
2I got from Dr. Smith, the O.K. to keep working.
3I got from Dr. Smith, the OK to keep working more.
4I got from Dr. Smith, the O.K. to keep working more.
5I got from Dr. Smith, the O.K. to keep working more, although I'm sick.
6I got from Dr. Smith, the O.K. to keep working more, although I'm so sick.

Желаемые выходные данные:

1I got from Dr. Smith, the OK to keep working.
2I got from Dr. Smith, the O.K. to keep working.
3I got from Dr.
Smith, the OK to keep working more.
4I got from Dr.
Smith the O.K. to keep working more.
5I got from Dr.
Smith, the O.K. to keep working more, although I'm sick.
6I got from Dr.
Smith, the O.K.
to keep working more, although I'm so sick.

Я пробовал следующий код:

sed -r ':a; /((\w)+[., ]+){11}/s/\./\r\n/; ta' grab.txt | tr '\r' '.' > output.txt

код дает следующие неточные результаты:

1I got from Dr. Smith, the OK to keep working.
2I got from Dr.
 Smith, the O.K. to keep working.
3I got from Dr.
 Smith, the OK to keep working more.
4I got from Dr.
 Smith, the O.K. to keep working more.
5I got from Dr.
 Smith, the O.K. to keep working more, although I'm sick.
6I got from Dr.
 Smith, the O.K. to keep working more, although I'm so sick.

Обратите внимание, что строки 1 и 2 имеют 10 слов, но строка 2 разделяется (кажется, что добавление точек к слову ... например, слово ОК ... делает этодумаю, что в строке больше слов, чем на самом деле).

Обратите внимание, что строка 6 на самом деле должна быть разделена на 3, потому что во второй строке содержится 11 слов, но по некоторым причинам ее нет.

Я ищу решение, в которое можно было бы направить трубку.

Спасибо.

Ответы [ 4 ]

3 голосов
/ 10 октября 2019

Простое решение с awk:

awk '{
  while (NF>10) {
    if (!(i=index($0,".")))
      break
    print substr($0,1,i)
    $0=substr($0,i+1)
    # trim leading blank(s)
    $1=$1
  }
  if ($0!="")
    print
}' file

Пока в строке более десяти слов , оно разбивается на первый период вдва;первая часть печатается, и строка обновляется второй частью и т. д.

Делать это с помощью sed, кстати, не очень хорошая идея.

2 голосов
/ 10 октября 2019

Ваша спецификация и ваш пример желаемого результата не совпадают.

В частности, "слова, определенные как что-либо между пробелами с обеих сторон" не совпадают

6I got from Dr.
Smith, the O.
K. to keep working more, although I'm so sick.`

Предполагаетсяваша спецификация правильна вместо вашего примера, вот решение для всех команд:

while read -a line
do set -- "${line[@]}"
   cnt=${#@}
   while (( ${#@} ))
   do printf "%s " "$1";
      case "$1" in
      *.) if (( cnt > 10 ))
          then echo
               cnt=${#@}
          fi ;;
      esac
      shift
   done
   echo
done < grab.txt

Вывод:

1I got from Dr. Smith, the OK to keep working.
2I got from Dr. Smith, the O.K. to keep working.
3I got from Dr.
Smith, the OK to keep working more.
4I got from Dr.
Smith, the O.K. to keep working more.
5I got from Dr.
Smith, the O.K.
to keep working more, although I'm sick.
6I got from Dr.
Smith, the O.K.
to keep working more, although I'm so sick.

Если вы просто хотели сделать это в sed -

$: cat tst
sed -E ':a
 /[.]*(\s+\S+){10,}/{
     s/[.]\s+/PLACEHOLDER\n/
     ta
 }
 s/PLACEHOLDER/. /g
' grab.txt

одной строкой:

$: sed -E ':a; /[.]*(\s+\S+){10,}/{ s/[.]\s+/PLACEHOLDER\n/;  ta; }; s/PLACEHOLDER/. /g;' grab.txt

Достаточно близко?

1 голос
/ 10 октября 2019

Следующая команда sed работает для предоставленного ввода.

cat <<EOF |
1I got from Dr. Smith, the OK to keep working.
2I got from Dr. Smith, the O.K. to keep working.
3I got from Dr. Smith, the OK to keep working more.
4I got from Dr. Smith, the O.K. to keep working more.
5I got from Dr. Smith, the O.K. to keep working more, although I'm sick.
6I got from Dr. Smith, the O.K. to keep working more, although I'm so sick.
EOF
sed '
    # hold the whole line
    h

    :again

    /\([^[:space:]]\{1,\}[[:space:]]\{1,\}\)\{9\}[^[:space:]]\{1,\}/{
        /\./!{
            s/.*/ERROR: no dot in pattern space to split ontu\nI have no idea what should I do here/
            p
            q
        }
        # add the newline behind dot in the hold space
        x
        # substitute first dot for a newline
        s/^\([^.]*\)\.[[:space:]]*/\1\n/
        x
        # remove everything before the dot in pattern space
        s///
        bagain
    }

    # ok, hold space has the result
    x
    # we removed dots from end of the lines
    # so we dont have to match them
    # restore them
    s/\x0a/.\n/g    
'

выведет:

1I got from Dr.
Smith, the OK to keep working.
2I got from Dr.
Smith, the O.K. to keep working.
3I got from Dr.
Smith, the OK to keep working more.
4I got from Dr.
Smith, the O.K. to keep working more.
5I got from Dr.
Smith, the O.
K. to keep working more, although I'm sick.
6I got from Dr.
Smith, the O.
K. to keep working more, although I'm so sick.

Сначала я удерживаю всю строку в пространстве удержания. Пространство удержания будет содержать результат.

Затем с \([^[:space:]]\{1,\}[[:space:]]\{1,\}\)\{9\}[^[:space:]]\{1,\} я сопоставляю 10 слов - 10 групп непробельных символов, разделенных пробелами. Если они есть, я проверяю, есть ли точка в линии, потому что, если ее нет, ну, я не знаю, что должно произойти, я просто выхожу.

Если есть точка,мы заменяем точку новой строкой в ​​удерживающем пространстве. И удалите точку со всем перед ней в пространстве образца и начните снова.

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

И, конечно, вкладыш:

sed 'h; :again; /\([^[:space:]]\{1,\}[[:space:]]\{1,\}\)\{9\}[^[:space:]]\{1,\}/{ /\./!{ s/.*/ERROR/p; q}; x; s/^\([^.]*\)\.[[:space:]]*/\1\n/; x;  s///; bagain}; x; s/\x0a/.\n/g'
1 голос
/ 10 октября 2019

Это может сработать для вас (GNU sed):

sed -E '/^\S+(\s+\S+){10}/s/\.\s/.\n/;P;D' file

Если текущая строка содержит 11 или более слов, замените первый период (и любой завершающий пробел) точкой и новой строкой,распечатать / удалить первую строку и повторить.

...