LINUX.ORG.RU

Простую регулярку

 ,


0

2

Есть переменная с текстом.

Нужно при помощи regexp получить строки, которые начинаются на определенные символы.

rgb6% другие слова

Как выше видно нужно оставить только строки, которые начинаются с букв rgb, потом цифрер и потом символ.

Мне кажется что нужно использовать символ ^

как здесь

Как это сделать?

PS: perl, awk, sed и grep — не предлагайте, потому что у меня нет доступа к консольной оболочке. Нужно на regexp



Последнее исправление: crazy (всего исправлений: 2)
Ответ на: комментарий от Leupold_cat

Не получается. Вылетает с ошибкой

Error in startup script: can't read "a": no such variable
    while executing

в коде написано было:

regexp {/(^rgb\d\W.*$)/gm} $var a
puts "$a"

Если я напишу вот так, то запускается, но отображается только первая строка:

regexp {rgb(.*?):\s(.*?)\s(.*?)\s(.*?)\s(.*?)\s(.*?)\s(.*?)*} $var a

Но если символы не %, а другие например < > :
То отображается все что начиная от rgb и до конца файла.

crazy
() автор топика
Ответ на: комментарий от crazy

Но если символы не %, а другие например < > :

Виноват, я сам двоеточие написал. Но всё равно отображается только или одна строка или всё от rgp до конца.

crazy
() автор топика
Ответ на: комментарий от crazy

У меня ^ никак не работает в скобках regexp в коде tcl. Что я делаю не так

crazy
() автор топика
Ответ на: комментарий от crazy

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

https://www.tcl.tk/man/tcl8.4/TclCmd/regexp.html

Я знаком с tcl совсем немного, но подозреваю, что вам понадобятся как минимум параметры -all, -line (если планируете использовать ^ для обозначения начала строки и $ для конца) и -inline.

У меня нет рядом интерпретатора, но предполагаю, что с моим выражением это должно выглядеть примерно как

regexp -all -inline -line {(^rgb\d\W.*$)} 
Leupold_cat ★★★★★
()
Последнее исправление: Leupold_cat (всего исправлений: 4)
set s [ gets stdin ]
if { [ regexp -expanded {^(rgb\d+)\s+(.*)$} $s all rgbXX tail ] } {
   puts "all line $all"
   puts "rgbXX part $rgbXX"
   puts "other part $tail"
}

как-то так примерно...но не проверял

MKuznetsov ★★★★★
()
Ответ на: комментарий от crazy

Не получается. Вылетает с ошибкой

результат regexp надо проверять..если строка не подходит под выражение, то переменные не будут созданы или изменены.

MKuznetsov ★★★★★
()
Ответ на: комментарий от Leupold_cat

У меня такой вариант ругается если с -inline

Error in startup script: regexp match variables not allowed when using -inline

Если без -inline, то вывод - это только одна последняя строка, которая подходит по регулярке.

crazy
() автор топика
Ответ на: комментарий от MKuznetsov

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

crazy
() автор топика

В Tcl есть более простые штуки - glob-ы, и по-моему для этой задачи их бы вполне хватило.

man n glob

Работает не только с файлами, так как многие команды, например string match берут глобы. Что-то вроде этого получится: rgb[0-9]%*

Переменную можно разбить на список строк командой split предварительно.

Xenius ★★★★★
()
Последнее исправление: Xenius (всего исправлений: 2)
Ответ на: комментарий от Xenius

А можно пример использования глобов без файлов, пожалуйста? я не нашел.

Я пока не понимаю, почему сделать ^ так сложно. Но вы навели меня на мысль и я осознал, что для меня подходит этот вариант, правда здесь не в регулярке:

set ssplit [split $input "\n"]
foreach rgb $ssplit {
        set rgbif [string first "rgb" $rgb]
        if {$rgbif == 0} {
                puts "$rgb"
        }
}
crazy
() автор топика
Ответ на: комментарий от Leupold_cat

Я тоже в этом плох, поэтому ценю любые советы, спасибо

crazy
() автор топика

Для подобного примитивного случая запускать шайтан regexp машину излишне мне кажется,любой strstr до rgb, затем схоронить всё до пробела или иного разделителя и всё. Будет быстрее и проще. Или какой scanline написать под конкретный случай. ИМХО. Хотя хз как в tcl с посимвольным обходом. Я тут вчера очень ругался когда открыл для себя лютые тормоза посимвольного обхода строк в lua, а шаблоны использовать тамошние лютый мазохизм такой же уродливый как regexp только ещё примитивный и не regexp вовсе. Уродливая няшечка ^.^ Ыыыы

LINUX-ORG-RU ★★★★★
()
Ответ на: комментарий от crazy

Много где в Tcl можно подставить glob, а у вас тут [0-9] нету после rgb. Например в операторе выбора глобы допустимы.

Сложно что-то подсказать, не понимая, зачем это всё нужно.

Xenius ★★★★★
()
Ответ на: комментарий от Xenius

Я не могу найти ему применение в примерах, кроме как с файлами

У меня тоже не совсем то что я хотел, из foreach не получается передать переменную. Может я сдамся и оставлю как есть, потому что замучался. Мастерства гугл-фу мне не хватает.

Сложно что-то подсказать, не понимая, зачем это всё нужно.

Я попробую обьяснить. Мне нужно сначала прочитать файл. Я это делаю при помощи open read close. Затем я получаю переменную, в которой список строк. Нужно этот список распарсить, так чтобы остались строки (которые начинаются с букв rgb, потом цифрер и потом символ.) Ну и потом нужно получить эти строки в переменные, чтобы каждая строка соответствовала какой-то переменной. У меня затык на всех трех этапах.

Вообще в идеале лучше получить все эти строки в массивы.

crazy
() автор топика
Ответ на: комментарий от crazy

Я попробую обьяснить. Мне нужно сначала прочитать файл. Я это делаю при помощи open read close. Затем я получаю переменную, в которой список строк. Нужно этот список распарсить, так чтобы остались строки (которые начинаются с букв rgb, потом цифрер и потом символ.) Ну и потом нужно получить эти строки в переменные, чтобы каждая строка соответствовала какой-то переменной. У меня затык на всех трех этапах.

set f [ open "файло" r ]
array set rgb {}
while { ! [ eof $f ] } {
   set s [ string trim [ gets $f ] ]
   if { $s == "" || [ string index $s 0 ] == "#" } {
      # skip empty and comments
      continue
   }
   set key [ lindex $s 0 ]
   if { [ regexp -expanded {^rgb\d+$} $s ] } {
      set rgb($key) [ lrange $s 1 end ]
   }
}
close $f
parray rgb
MKuznetsov ★★★★★
()
Последнее исправление: MKuznetsov (всего исправлений: 2)
Ответ на: комментарий от MKuznetsov

Никак не могу понять, что не так делаю.

Код вроде выполняется, но ничего не показывает. $s - получает список. $key - оставляет в списке только первое слово для каждой строки. А дальше не удалось выяснить

сама регулярка тоже не срабатывает, когда я делаю так

regexp -expanded {^rgb\d+$} $s a
puts $a
crazy
() автор топика
Ответ на: комментарий от MKuznetsov

Пробовал к $key, но ошибка та же самая

% wish8.6 test11.tcl
Error in startup script: can't read "a": no such variable
    while executing
"puts $a        "
    ("while" body line 9)
    invoked from within
"while { ! [ eof $f ] } {
   set s [ string trim [ gets $f ] ]
   if { $s == "" || [ string index $s 0 ] == "#" } {
      # skip empty and comments
   ..."
    (file "test11.tcl" line 5)
crazy
() автор топика
Ответ на: комментарий от crazy

потом цифрер и потом символ

Какой символ-то? А если например rgb2⁹ это считается или нет? А если ’rgb2 ’ (то есть пробел)? Так-то пробел тоже символ…

Xenius ★★★★★
()
Ответ на: комментарий от Xenius

Нет. У меня только : или %. Но вообще я имею в виду простые символы ! @ # $ % ^ & * ( ) \ ? > < и тд. Другие не обязательно. Пробел не символ, для него должны быть какие-то другие классы - [[:blank:]] или [[:space:]]

crazy
() автор топика
Ответ на: комментарий от MKuznetsov

вы программу пишите методом опроса населения ? :-)

Простите меня, я в программировании полный ноль и могу легко совершать глупости ;)

у вас там нет переменной «a» потому интерпретатор и ругается

Я попробовал сделать переменную a

set key [ lindex $s 0 ]
set a [ regexp -expanded {^rgb\d+$} $key ]
puts $a

В результате я получил список с содержимым 0 в каждой строке.

crazy
() автор топика
Ответ на: комментарий от crazy

Подскажите, пожалуйста, как сделать правильно.

правильно, это побольше читать чтобы поменьше писать :-)

читаем документацию: regexp возвращает результат операции - 0 (false) если выражение не подходит под шаблон или 1 (true) если подходит.

точная цитата «Determines whether the regular expression exp matches part or all of string and returns 1 if it does, 0 if it does not, unless -inline is specified (see below)»

в примере который я давал:

if { [ regexp -expanded {^rgb\d+$} $key ] } {
      set rgb($key) [ lrange $s 1 end ]
}

происходит следующее - если ключ похож на «rgb1321» (буквы rgb и следующие за ними цифры, то есть regexp вернёт 1) то в массив заносится значение (оставшаяся часть строки) с этим ключом.

MKuznetsov ★★★★★
()
Ответ на: комментарий от MKuznetsov

Хорошо, тогда обьясните мне следующее. Может быть, я как-то неправильно прочитал массив, но при выполнении puts $rgb($key) получаю пустое значение.

crazy
() автор топика
Ответ на: комментарий от crazy

Там нет спецсимвола потому что, регексп ловит только строки с цифрой без символа.

Надо так:

#!/usr/bin/env tclsh

set fn [file normalize [lindex $argv 0]]
if {![file exist $fn]} {
	puts stderr "Error: File does not exist: `$fn`"
	puts stderr "Usage: $argv0 filename"
	exit 1
}

set fd [open $fn r]
set data [read $fd]
close $fd

set result {}
foreach line [split $data \n] {
	if {[regexp {^rgb\d+[!-/:-@[-`{|}~]} $line]} {
		lappend result $line
	}
}

puts [join $result \n]

Строки с rgb123% hello, где цифр несколько, должны входить в набор или нет? Если нет, то убери + после \d в регекспе.

Xenius ★★★★★
()
Последнее исправление: Xenius (всего исправлений: 3)
Ответ на: комментарий от Xenius

Этот код работает для меня, спасибо!

А с массивами почему-то не работает. Я так и не понял что не так.

crazy
() автор топика
Ответ на: комментарий от crazy

А с массивами почему-то не работает. Я так и не понял что не так.

Учти что массивы в Tcl ассоциативные, то есть это скорее хеш-таблицы. Если тебе нужно именно это, то есть доступ по произвольной строке как индексу, то ещё подходит dict, и он лучше так как его можно передавать в процедуры. А если тебе нужен аналог обычного массива, лучше брать list, все операции нужные для массивов у него есть.

готовый код для массива я не предложу так как не знаю какие тебе нужны индексы. Цифры из той строки rgb…% ? мне же непонятно нафига тебе эти строки.

Xenius ★★★★★
()
Ответ на: комментарий от Xenius

Я думал о сложении результата в массив, если вдруг дальше понадобится использовать какую-то конкретную строку (переменную) для чего-то. Например, строку номер 3 нужно поместить в одну функцию, а 4 в другую. Такую ситуацию я не могу точно объяснить, потому что это только в теории. А свою задачу я уже решил и мне этого хватило. Спасибо, за подробные объяснения.

не знаю какие тебе нужны индексы.

Для массива не имеет значения какие индексы в переменных. Так что это могут быть обычные цифры, которые нумеруют количество содержимого (строк), я это так представлял.

rgb(1)
rgb(2)
…и тд..

crazy
() автор топика
Ответ на: комментарий от crazy

Я думал о сложении результата в массив, если вдруг дальше понадобится использовать какую-то конкретную строку (переменную) для чего-то. Например, строку номер 3 нужно поместить в одну функцию, а 4 в другую.

Для этого подходит обычный список и lindex или lrange. В моём коде например из списка argv берётся первый элемент (первый параметр командной строки)

Xenius ★★★★★
()
Последнее исправление: Xenius (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.