URL: https://www.opennet.me/cgi-bin/openforum/vsluhboard.cgi
Форум: vsluhforumID9
Нить номер: 7261
[ Назад ]

Исходное сообщение
"Поиск и выкусывание нужного текста из файла"

Отправлено agalin , 18-Мрт-08 17:26 
Помогите реализовать с помощью awk & sed или Perl.
Есть текстовый файл с содержимым такого вида:

        .......
abba babba affa aggga assa
BMW    mercedes benz.car germany
BMW    zma rexton.zma russia
tadda galla dalla malla
       ........

В этом файле между словами BMW и mercedes несколько пробелов, а между словами mercedes и benz стоит одинарный пробел, а между car и germany - несколлько пробелов. Нужно вытащить из этого файла и поместить в другой файл записи типа "mercedes benz", отыскав эту строчку по начальному полю "BMW" и комбинации ".car".
Помогите пожалуйста это сделать. Трудность вызывает то, что mercedes benz содержит пробел между словами, а так же то что нужно избавиться от .car.
Заранее спасибо!


Содержание

Сообщения в этом обсуждении
"Поиск и выкусывание нужного текста из файла"
Отправлено agalin , 18-Мрт-08 17:33 
Известно, что интересующая нас запись стоит сразу же после BMW, но заранее не известно, состоит она из одного слова (mercedes) или из двух разделенных пробелом (mercede benz). Нужно вытащить то, что лежит между BMW и .car.

"Поиск и выкусывание нужного текста из файла"
Отправлено angra , 18-Мрт-08 17:43 
>отыскав эту строчку по начальному полю "BMW" и комбинации ".car".

perl -ne 'print "$1\n" if /^BMW\s+(.*?)\.car/'

Лучше конечно прочитать man perlre для понимания. Но все же прокоментирую
^ - начало строки
BMW - дословно
\s+ - один и больше пробельных символов
(.*?) - _нежадный_ захват всего подряд
\.car - .car
Разница между жадным и нежадным захватом:
$ perl -ne 'print "$1\n" if /^BMW\s+(.*?)\.car/'
BMW    mercedes benz.car benz.car germany
mercedes benz
$ perl -ne 'print "$1\n" if /^BMW\s+(.*)\.car/'
BMW    mercedes benz.car benz.car germany
mercedes benz.car benz


"Поиск и выкусывание нужного текста из файла"
Отправлено agalin , 18-Мрт-08 19:01 
Спасибо за быстрый ответ!
Пытаюсь реализовать с помощью sed:
sed -ne '/^BMW\s+(.*?)\.car/p' test.txt    не ищет. В чем проблема?

"Поиск и выкусывание нужного текста из файла"
Отправлено rWizard , 18-Мрт-08 22:14 
>Спасибо за быстрый ответ!
>Пытаюсь реализовать с помощью sed:
>sed -ne '/^BMW\s+(.*?)\.car/p' test.txt    не ищет. В чем проблема?
>

Видимо в том, что sed использует другую билиотеку регулярных выражений - соответствующую стандарту IEEE Std 1003.2
man re_format

Регулярные выражения perl имеют больший функционал.


"Поиск и выкусывание нужного текста из файла"
Отправлено stas , 19-Мрт-08 00:29 
>Спасибо за быстрый ответ!
>Пытаюсь реализовать с помощью sed:
>sed -ne '/^BMW\s+(.*?)\.car/p' test.txt    не ищет. В чем проблема?
>

sed -n 's/^BMW\s\+\(.*\)\.car.*/\1/p' test.txt


"Поиск и выкусывание нужного текста из файла"
Отправлено agalin , 19-Мрт-08 12:00 
>>Спасибо за быстрый ответ!
>>Пытаюсь реализовать с помощью sed:
>>sed -ne '/^BMW\s+(.*?)\.car/p' test.txt    не ищет. В чем проблема?
>>
>
>sed -n 's/^BMW\s\+\(.*\)\.car.*/\1/p' test.txt

Все равно не ищет.


"Поиск и выкусывание нужного текста из файла"
Отправлено phpcoder , 19-Мрт-08 12:06 
>>>Спасибо за быстрый ответ!
>>>Пытаюсь реализовать с помощью sed:
>>>sed -ne '/^BMW\s+(.*?)\.car/p' test.txt    не ищет. В чем проблема?
>>>
>>
>>sed -n 's/^BMW\s\+\(.*\)\.car.*/\1/p' test.txt
>
>Все равно не ищет.

Попробуйте так: sed -n 's/^BMW[ \t]*\(.*\)\.car.*/\1/p'



"Поиск и выкусывание нужного текста из файла"
Отправлено agalin , 19-Мрт-08 12:56 
>Попробуйте так: sed -n 's/^BMW[ \t]*\(.*\)\.car.*/\1/p'

Спасибо! Работает, но выдает нужное поле в той колонке, из которой было вырезано - в данном случае в колонке 2,то есть результат:

$> sed -n 's/^BMW[ \t]*\(.*\)\.car.*/\1/p'
$>      mercedes benz



"!!! усывание нужно"
Отправлено Andrey Mitrofanov , 19-Мрт-08 14:09 
>Спасибо! Работает, но
>,то есть результат:

Стоп! Всем спасибо, ошибка найдена: пользователь не включил мозги и не rtfm.
Всем - спасибо, расходитесь уже, не задерживайтесь. :-/


"!!! усывание нужно"
Отправлено agalin , 19-Мрт-08 15:01 
Спасибо! Результат есть!


"Поиск и выкусывание нужного текста из файла"
Отправлено agalin , 19-Мрт-08 11:56 
>perl -ne 'print "$1\n" if /^BMW\s+(.*?)\.car/'

Спасибо! Работает!
Есть еще один вопрос. Пусть есть файл вида:

                             ..................................

Name                    Interval     Datum Name     Ellipsoid Name     Semi-major axis
__________________________________________________________________________________________________________
Aurora Secondary        10 min       WGW-84         WGW-84             6378137.0000    

Name                    Inv. flattening  Shift             Shift Type        Projection    
__________________________________________________________________________________________________________
Aurora Secondary        298.2572221      WGW-84 -> HDA-90  Bursa Wolf        ZONE 52S          
                            
                            ...................................

Как например искать Shift Type, а выводить то, что написано под Shift Type - Bursa Wolf?
Слово Bursa Wolf содержит пробел между словами. Данные, которые требуется вытаскивать, ищутся по заголовку (например Shift Type), а берется то, что располагается точно снизу - Bursa Wolf. Слова могут состоят из пробелов. Как это сделать?


"Поиск и выкусывание нужного текста из файла"
Отправлено agalin , 19-Мрт-08 12:14 
К сожалению все сместилось - не удалось показать файл. Попробую еще раз:

Datum Name     Ellipsoid Name
WGW-84           WGW-84

Shift            Shift Type
HDA-90     Bursa Wolf


"Поиск и выкусывание нужного текста из файла"
Отправлено phpcoder , 19-Мрт-08 12:15 
>Datum Name     Ellipsoid Name
>WGW-84           WGW-84
>
>Shift            >Shift Type
>HDA-90     Bursa Wolf

Сколько строк? 5?


"Поиск и выкусывание нужного текста из файла"
Отправлено Arpo , 19-Мрт-08 12:18 
>К сожалению все сместилось - не удалось показать файл. Попробую еще раз:
>
>
>Datum Name     Ellipsoid Name
>WGW-84           WGW-84
>
>
>Shift            
>Shift Type
>HDA-90     Bursa Wolf

Разделитель полей TAB или пробел??


"Поиск и выкусывание нужного текста из файла"
Отправлено agalin , 19-Мрт-08 12:43 
>Разделитель полей TAB или пробел??

Разделитель полей - множественные пробелы. Количество строк в файле заранее не известною Здесь приведен лишь фрагмент файла.
Существенная деталь:
Bursa Wolf располагается точно под Shift Type (то есть буква B под буквой S), WGW-84 располагается точно под Ellipsoid Name (то есть буква W под буквой E).  
Ellipsoid Name и Shift Type не являются последними столбцами - столбцы есть и справа.
Между строками WGW-84 и Shift расстояние -  2 пустые строки

       .................
Datum Name     Ellipsoid Name     ....
WGW-84           WGW-84


Shift            Shift Type       ....  
HDA-90     Bursa Wolf
     ...................


"Поиск и выкусывание нужного текста из файла"
Отправлено phpcoder , 19-Мрт-08 12:34 
[c0der@xxx ~]$ cat TEST
Name                    Interval     Datum Name     Ellipsoid Name
Semi-major axis
__________________________________________________________________________________________________________
Aurora Secondary        10 min       WGW-84         WGW-84
6378137.0000

Name                    Inv. flattening  Shift             ShiftType        Projection
__________________________________________________________________________________________________________
Aurora Secondary        298.2572221      WGW-84 -> HDA-90  Bursa Wolf       ZONE 52S
[c0der@xx ~]$ sed -n '/ShiftType/{n;n;s/[ t]\{2,\}/|/g;s/[^|]*|[^|]*|[^|]*|\([^|]*\)|.*/\1/p}' <TEST
Bursa Wolf

Форматирование, возможно, всё испортит... Короче, надо вас сами пробовать. Вот дока по sed: http://www.cs.utk.edu/~vose/c-stuff/sed_tutorial.html Читайте, пробуйте и у вас всё получится.

Вот алгоритм решения вашей задачи на sed:
- найти строку, в которой есть фраза ShiftType (/ShiftType/)
- считать следующую строку (n)
- считать следующую строку (n)
- теперь строка через одну от найденной у нас. Нужно "выкусить из неё 4 столбец
  + заменяем повторяющиеся два и более раз пробелы/табуляции во всей строке на что-то уникальное (s/[ \t]\{2,\}/|/g)
  + теперь наш уникальный знак является разделителем полей, по регэкспу выкусываем из него только четвёртое поле
- выводим результат


"Поиск и выкусывание нужного текста из файла"
Отправлено Arpo , 19-Мрт-08 13:03 
>[оверквотинг удален]
>- найти строку, в которой есть фраза ShiftType (/ShiftType/)
>- считать следующую строку (n)
>- считать следующую строку (n)
>- теперь строка через одну от найденной у нас. Нужно "выкусить из
>неё 4 столбец
>  + заменяем повторяющиеся два и более раз пробелы/табуляции во всей
>строке на что-то уникальное (s/[ \t]\{2,\}/|/g)
>  + теперь наш уникальный знак является разделителем полей, по регэкспу
>выкусываем из него только четвёртое поле
>- выводим результат

может так
-bash-3.00$ cat 111.txt
Datum Name   Ellipsoid Name     ....
WGW-84       WGW-84


Shift      Shift Type       ....
HDA-90     Bursa Wolf
     ...................

-bash-3.00$ cat 111.txt |sed -n '/Shift\ Type/ {
n
s/[ \t]\{2,\}/+/g
p
}'|awk -F+ '{print $2}'


"Поиск и выкусывание нужного текста из файла"
Отправлено Arpo , 19-Мрт-08 13:05 
>[оверквотинг удален]
>Shift      Shift Type    
>  ....
>HDA-90     Bursa Wolf
>     ...................
>
>-bash-3.00$ cat 111.txt |sed -n '/Shift\ Type/ {
>n
>s/[ \t]\{2,\}/+/g
>p
>}'|awk -F+ '{print $2}'

Это 100% работает в Solaris10


"Поиск и выкусывание нужного текста из файла"
Отправлено agalin , 19-Мрт-08 13:47 
>>-bash-3.00$ cat 111.txt |sed -n '/Shift\ Type/ {
>>n
>>s/[ \t]\{2,\}/+/g
>>p
>>}'|awk -F+ '{print $2}'
>
>Это 100% работает в Solaris10

Правильно ли я понял?

$> cat test.txt |sed -n '/Shift\ Type/{ns/[ \t]\{2,\}/+/gp}'|awk -F+ '{print $2}'


"Поиск и выкусывание нужного текста из файла"
Отправлено Arpo , 19-Мрт-08 14:46 
>[оверквотинг удален]
>>>n
>>>s/[ \t]\{2,\}/+/g
>>>p
>>>}'|awk -F+ '{print $2}'
>>
>>Это 100% работает в Solaris10
>
>Правильно ли я понял?
>
>$> cat test.txt |sed -n '/Shift\ Type/{ns/[ \t]\{2,\}/+/gp}'|awk -F+ '{print $2}'

У меня так не работает поетому пришлось писать на разных строках...



"Поиск и выкусывание нужного текста из файла"
Отправлено phpcoder , 19-Мрт-08 14:52 
>>$> cat test.txt |sed -n '/Shift\ Type/{ns/[ \t]\{2,\}/+/gp}'|awk -F+ '{print $2}'

Когда автор слепил весь текст в одну строку и у меня не стало работать ;) Потому что для разделения команд нужно использовать точку с запятой (ну или на новой строке писать, чтобы солярка понимала).

>У меня так не работает поетому пришлось писать на разных строках...

Автор не сообщил ни версию sed'а ни ОС, так что я привёл пример на основе Linux'а. По идее, если автору нужно это на Соляре запускать, то он должен был это сообщить.


"Поиск и выкусывание нужного текста из файла"
Отправлено agalin , 19-Мрт-08 15:03 
>Соляре запускать, то он должен был это сообщить.

Спасибо за замечание. Да, мне нужно запустить на Solaris 10.


"Поиск и выкусывание нужного текста из файла"
Отправлено phpcoder , 19-Мрт-08 14:53 
>-bash-3.00$ cat 111.txt |sed -n '/Shift\ Type/ {
>n
>s/[ \t]\{2,\}/+/g
>p
>}'|awk -F+ '{print $2}'

sed -n '/Shift\ Type/ {
n
s/[ \t]\{2,\}/+/g
p
}' <111.txt |awk -F+ '{print $2}'

cat тут совершенно не нужен.


"Поиск и выкусывание нужного текста из файла"
Отправлено Arpo , 19-Мрт-08 15:03 
>[оверквотинг удален]
>>p
>>}'|awk -F+ '{print $2}'
>
>sed -n '/Shift\ Type/ {
>n
>s/[ \t]\{2,\}/+/g
>p
>}' <111.txt |awk -F+ '{print $2}'
>
>cat тут совершенно не нужен.

Это кому как удобно...ИМХО


"Поиск и выкусывание нужного текста из файла"
Отправлено agalin , 19-Мрт-08 15:31 
>Это кому как удобно...ИМХО

Спасибо! Извините, но есть небольшая корректировка к файлу. В файле есть разделитель между
Datum Name и WGW-84, Shift и HDA-90 и т.д.
       .................
Datum Name     Ellipsoid Name     ....
---------------------------------------------
WGW-84           WGW-84


Shift            Shift Type       ....
---------------------------------------------
HDA-90     Bursa Wolf
     ...................

Получилось, что скрипт вытаскивает этот разделитель теперь :-(


"Поиск и выкусывание нужного текста из файла"
Отправлено phpcoder , 19-Мрт-08 15:33 
>Спасибо! Извините, но есть небольшая корректировка к файлу. В файле есть разделитель
>между [...]
>Получилось, что скрипт вытаскивает этот разделитель теперь :-(

А у меня это было предусмотрено ;-)) Сличайте мой скрипт и скрипт от Arpo. ;-))

Подсказка: нужно два n


"Поиск и выкусывание нужного текста из файла"
Отправлено agalin , 19-Мрт-08 15:57 
>Подсказка: нужно два n

Oгромное спасибо, работает! :-) А если Shift Type встречается несколько раз, как вывести только то, что встретилось первый раз. Заранее спасибо!


"Поиск и выкусывание нужного текста из файла"
Отправлено phpcoder , 19-Мрт-08 16:00 
>А если Shift Type встречается несколько раз, как вывести только то, что встретилось первый раз. Заранее спасибо!

Добавьте q по вкусу :-)



"Поиск и выкусывание нужного текста из файла"
Отправлено agalin , 19-Мрт-08 16:05 
>Добавьте q по вкусу :-)

Спасибо! И последнее - как теперь посчитать количество совпадений (то что было найдено при помощи sed и awk)?


"Поиск и выкусывание нужного текста из файла"
Отправлено phpcoder , 19-Мрт-08 16:06 
>Спасибо! И последнее - как теперь посчитать количество совпадений (то что было
>найдено при помощи sed и awk)?

Трудно сказать, вариантов много и мы не знаем деталей. Можно в awk прям и считать, что он там находит, можно в шелле переменную увеличивать. Скорее всего вам wc -l нужно.. он строчки считает.


"Поиск и выкусывание нужного текста из файла"
Отправлено agalin , 19-Мрт-08 16:24 
>Трудно сказать, вариантов много и мы не знаем деталей. Можно в awk
>прям и считать, что он там находит, можно в шелле переменную
>увеличивать. Скорее всего вам wc -l нужно.. он строчки считает.

И еще один момент: если есть несколько реализаций поски текста с помощью sed&awk и есть несколько реализаций поиска в Perl, как их лучше объединить?


"Поиск и выкусывание нужного текста из файла"
Отправлено agalin , 19-Мрт-08 16:26 
Хочу добавить, что конечной целью является построение отчетов.



"Поиск и выкусывание нужного текста из файла"
Отправлено phpcoder , 19-Мрт-08 16:29 
>И еще один момент: если есть несколько реализаций поски текста с помощью
>sed&awk и есть несколько реализаций поиска в Perl, как их лучше
>объединить?

Ну, например, так:

FROM_PERL=`perl ... | wc -l`
FROM_AWK=`awk ... | wc -l`
FROM_SED=`sed ... | wc -l`

printf 'Всего найдено %u\n' "`expr $FROM_PERL + $FROM_AWK + $FROM_SED`"



"Поиск и выкусывание нужного текста из файла"
Отправлено agalin , 19-Мрт-08 16:44 
Спасибо всем авторам за помощь! Все очень сильно пригодилось! Было интересно и познавательно! :-) Спасибо!



"Поиск и выкусывание нужного текста из файла"
Отправлено agalin , 19-Мрт-08 21:15 
Попутно встретилась еще одна проблема. Если файл имеет немного другое строение:
       ...........................

*****************Projection******************
Datum Name     Ellipsoid Name     ....
---------------------------------------------
WGW-84           Bursa Wolf
QWQ90             Flow Burs  
...                  ...

*****************Translation*****************
Shift            Shift Type       ....
---------------------------------------------
HDA-90     Bursa Wolf
FDS-70       Flow Burs
...            ...  

     .............................

Нужно в секции Projection отыскать Ellipsoid Name и вывести все поля под ним - Bursa Wolf,Flow Burs и т.д. до секции Translation. Количество этих полей под Ellipsoid Name заранеее не известно.

Если в примере ранее использовалось n;n для считывания вниз 2-строк, то теперь не ясно как сместиться вниз на заранее не известное количество строк и вывести их.


"???"
Отправлено Yes , 19-Мрт-08 22:04 
>Попутно встретилась еще одна проблема. Если файл имеет

Гм, Вам там небольшой Windows на sed-е написать не надо будет? А то одна строчка скрипта всё обрастает "подробностями", а понимание не приходит??


"Поиск и выкусывание нужного текста из файла"
Отправлено agalin , 20-Мрт-08 00:05 
Думаю, что нужно обозначить некий блок /Projection/,/Translation/ и уже в этом блоке применить:
$> cat test.txt | sed -n '/Ellipsoid\ Name/ {n;n;s/[ \t]\{2,\}/+/g;p;}'|awk -F+ '{print $2}'
Но как передать этот блок sed?

"Поиск и выкусывание нужного текста из файла"
Отправлено phpcoder , 20-Мрт-08 08:31 
У меня работает, вот так:

[c0der@xxx ~]$ cat TEST

*****************Projection******************
Datum Name     Ellipsoid Name     ....
---------------------------------------------
WGW-84           Bursa Wolf
QWQ90             Flow Burs
...                  ...

*****************Translation*****************
Shift            Shift Type       ....
---------------------------------------------
HDA-90     Bursa Wolf
FDS-70       Flow Burs
You have new mail.                                                                                                    
[c0der@xxx ~]$ sed -n '/Projection/{n;/Ellipsoid Name/{n;:l n;/Translation/q;s/[^[:space:]]\+[[:space:]]\+\(.*\)/\1/p;bl}}' TEST
Bursa Wolf
Flow Burs
...
[c0der@xxx ~]$

Разбирайтесь как работает, адаптируйте под ваш Солярис :)

В кратце: тут организован этакий цикл -- до тех пор пока в строке нет слова Translation выполняются некие действия (замена, печать).



"Поиск и выкусывание нужного текста из файла"
Отправлено agalin , 20-Мрт-08 17:51 
>В кратце: тут организован этакий цикл -- до тех пор пока в
>строке нет слова Translation выполняются некие действия (замена, печать).

Сложно понять 2 вложения! А не покажете для начинающего только одно вложение? Например по Projection найти Bursa Wolf?


"Спасибо всем!"
Отправлено agalin , 21-Мрт-08 21:53 
Спасибо всем! Было позновательно и интересно! :-) Отдельное спасибо phpcoder'у за терпение! :-) Тема закрыта!