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

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

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)
Ответ на: комментарий от 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
() автор топика

Для подобного примитивного случая запускать шайтан 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
() автор топика
Ответ на: комментарий от crazy

в примере кода не $s, а $key конечно-же должно быть…регулярку применяем к ключу, а не ко всей строке

MKuznetsov ★★★★★
()
Последнее исправление: MKuznetsov (всего исправлений: 1)
Ответ на: комментарий от 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
() автор топика
Ответ на: комментарий от 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 ★★★★★
()
Ответ на: комментарий от 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)
Ответ на: комментарий от crazy

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

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

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

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

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

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

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

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

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

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

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

Xenius ★★★★★
()
Последнее исправление: Xenius (всего исправлений: 1)