I'm trying to export a css rule from a css file with awk but I am not able to do it. I need only the rules containing the "background-image" line.
#rule{
...
background-image: url(path);
}
Here's what I have tried so far:
awk '/^[#].*{.*background-image.*/','/}/' css/file.css
What am I doing wrong?
At this moment I got the best result using:
/^[#A-Za-z.]/ { accum = 1; }
accum == 1 { css = css $0 "\n"; }
accum == 1 && /background-image/ { found = 1; }
/\}/ { accum = 0; if (found == 1) print css; found = 0; css = ""; }
and it allows me to get a full block with all the selectors
Turn accumulation on after matching an open brace. Accumulate all lines while flag is on. Turn off after closing brace is seen. Print only if background-image found during accumulation. If you want to include lines before the match you do do something like this.
{ line4 = line3; line3 = line2; line2 = line1; line1 = $0 "\n"; }
/\{/ { accum = 1; head = line4 line3 line2 line1; }
accum == 1 { css = css $0 "\n"; }
accum == 1 && /background-image/ { found = 1; }
/\}/ {
accum = 0;
if (found == 1) print head css;
found = 0; css = "";
}
You had said in comments "I need the full block from # (or . ) to }" but I'm getting the impression that you really just want this.
/\{/ { selector = $0 }
/background-image/ { print selector "\n" $0 "\n}\n" }
Related
Let's say I have this:
something,"another thing"
This can be split easily with a normal split function.
Now I want to have more complicated syntax and I do:
something,"in a string, oooh",rgba(4,2,0)
This does not work with a regular split function.
I tried using things like replacing commas inside of specific types of tokens, but that became too over-complicated and I feel there has to be a better way.
Then I tried with regular expressions, which worked, until I had to add a new feature, which wouldn't work with the regexp I had (which was pretty bad), also regexp matches can be slow, and this is supposed to be as fast as possible.
What would be a better way to solve this?
Here is the source repo for extra context https://github.com/hyprland-community/hyprparse
And the format in question is the hyprland config format
Iterate over the string keeping a context state:
None
Inside a "..."
Inside a (...)
Inside a context, comma has no separator meaning.
Limitations: This is a midnight hack!
See also Rust Playground
fn split(s: String) -> Vec<String> {
let mut context = None;
let mut i = 0;
let mut start = 0;
let mut items = Vec::new();
for c in s.chars() {
if context == Some('"') {
if c == '"' {
context = None;
}
i = i+1;
continue;
} else if context == Some('(') {
if c == ')' {
context = None;
}
i = i+1;
continue;
}
if c == '"' || c == '(' {
context = Some(c);
}
if c == ',' && context.is_none() {
items.push(s[start..i].to_string());
start = i + 1;
}
i = i+1;
}
items.push(s[start..i].to_string());
items
}
fn main() {
let s = "something,\"in a string, oooh\",rgba(4,2,0)".to_string();
println!("{:?}", split(s));
// -> ["something", "\"in a string, oooh\"", "rgba(4,2,0)"]
}
Thanks for all the help everyone, I eventually came up with my own solution with the help of people I knew IRL, here is my solution:
fn previous_rgb(index: usize, chars: Vec<char>) -> bool {
let string: String = chars[index-3..index].iter().collect();
let string = string.as_str();
if string == "gba" || string == "rgb" {
true
} else {
false
}
}
fn splitter<Str: ToString>(s: Str) -> Vec<String> {
let mut is_in_rgb = false;
let mut is_in_str = false;
let mut last = 0;
let chars: Vec<_> = s.to_string().chars().collect();
let mut final_str = vec![];
for (index, c) in chars.iter().enumerate() {
if *c == '(' && previous_rgb(index, chars.clone()) && !is_in_str {
is_in_rgb = true;
} else if *c == ')' && is_in_rgb && !is_in_str {
is_in_rgb = false;
} else if *c == '"' && is_in_str {
is_in_str = false;
} else if *c == '"' && !is_in_str {
is_in_str = true;
} else if *c == ',' && !is_in_str && !is_in_rgb {
final_str.push(chars[last..index].iter().collect());
last = index + 1
};
}
final_str.push(chars[last..].iter().collect());
final_str
}
fn main() {
let splitted = splitter(r#"test,test: rgba(5,4,3),"test2, seperated""#);
println!("{splitted:?}");
}
I am making a converter to convert a string to binary and I want to change the color of every 8th character of the resulting binary conversion result to red to symbolize the beginning of each ascii character. The user enters a string a text input and the converted result is displayed in a text area like so:
Every 8th 0 or 1 should be red.
I'm not sure where to begin and is this even possible? And if I were to reverse the converter (user enters binary and its converted to ascii characters) could it still work? Thanks.
Edit:
I am adding "<font color='red'>" and "</font>" to the beginning and end of every eighth binary digit but the result displayed is literally "<font color='red'>0</font>", it is not applying the html styling.
My TextInput sets the TextArea.text whenever the user types using a C++ function.
TextInput {
...
onTextChanged: {
uiText.setBinaryString(myTextInput.text)
myTextAreaText.text = uiText.getBinaryString()
}
}
C++ functions
void UITextConnector::setBinaryString(QString s)
{
binaryString = convertToBinary(s);
}
QString UITextConnector::getBinaryString()
{
return binaryString;
}
QString UITextConnector::convertToBinary(QString qs)
{
std::string resultString;
if (binaryMode) {
std::string qStringConverted = qs.toStdString();
for (std::size_t i = 0; i < qStringConverted.size(); i++) {
std::bitset<8> b(qStringConverted.c_str()[i]);
std::string nextBinary = b.to_string();
nextBinary = "<font color='#00AA00'>" + nextBinary.substr(0,1) + "</font>" + nextBinary.substr(1);
resultString += nextBinary;
}
} else {
std::string qStringConverted = qs.toStdString();
for (std::size_t i = 0; i < qStringConverted.size() ; i = i + 8) {
resultString += UITextConnector::strToChar(qStringConverted.substr(i, i+8).c_str());
}
}
return QString::fromStdString(resultString);
}
However, this only works if I use a label but not when I use a textArea.
Since you didn't provide any source or whatever it is too difficult to understand what is your fail. Anyway, I would do that in the following way:
TextArea {
id: txt
anchors.fill: parent
anchors.margins: 10
textFormat: TextEdit.RichText
text: ""
function setText(str)
{
var arr = str.match(/.{1,8}/g) || [];
var result = "";
for(var index in arr)
{
result += "<font color='red'>" + arr[index].substring(0, 1) + "</font>" + arr[index].substring(1);
}
txt.text = result;
}
Component.onCompleted: {
txt.setText("aaaaaaaabbbbbbbbccccccccdddd");
}
}
I got this kind of CSV file:
name,x-extension,value,extra
"Roger","9890","",""
"Nicole","9811","president, ceo",""
...
Now, I want the find the maximum size of each field in the file. So I used this awk script:
Updated script:
NR==1 {
gsub(/\r/,"",$0) #remove linefeed from last field name
for (n = 1; n <= NF; n++) {
colname[n]=$n;
maxlen[n]=-1;
}
nbrField = NF; # will get bump +2 by the new FS
FS="\",\"|^\"|\"$";
}
NR>1 {
for (n = 2; n <= nbrField+1; n++) {
if (length($n)>maxlen[n-1]) {
maxlen[n-1]=length($n);
}
}
}
END {
for(i = 1; i <= nbrField; i++) {
printf "%s : %s\n", colname[i], maxlen[i]
}
}
The problem a got is I need to change the field separator AFTER reading the first line because as you can see, the header don't use double quote for field delimiter and there is coma INSIDE some field.
I tried to play with this -F option on my awk command line but I can't find the right combination of regex to do the trick..
> awk -F'", "|^"|"$' -f myprog mydata ==>(don't work)
Help! :-)
Change FS in the block that processes the first line:
NR==1 {
for(n = 1; n <= NF; n++) {
colname[n]=$n
}
FS="\",\"|^\"|\"$"
}
I prefer to use a real CSV parser for CSV data. For example, Perl:
perl -MText::CSV -MList::Util=max -nE '
BEGIN {$csv = Text::CSV->new({binary=>1})}
$csv->parse($_);
#row = $csv->fields();
if ($. == 1) {
#h = #row; $n = $#row;
}
else {
$max{$h[$_]} = max($max{$h[$_]}, length $row[$_]) for (0..$n)
}
END {
while (($k,$v) = each %max) {say join ":", $k, $v}
}
' << DATA
name,x-extension,value,extra
"Roger","9890","",""
"Nicole","9811","president, ceo",""
DATA
value:14
name:6
extra:0
x-extension:4
I have this file called ab.exe it contains this in hexadecimal
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000BBAAE8CAFDFFFF83C408000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000054AAE8CAFDFFFF83C40800000000000000000000000000000000000000000000000000000000000000000000000000AAE8CAFDFFFF83C4088D000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
I have this code in c++ that is suppose to detect if a string of hexadecimal is in a file or not and if it is add it to the list box.
array<Byte>^ target1 = { 0xAA,0xE8,0xCA,0xFD,0xFF,0xFF,0x83,0xC4,0x08,0x8D };
array<Byte>^ target2 = { 0x54,0xAA,0xE8,0xCA,0xFD,0xFF,0xFF,0x83,0xC4,0x08 };
array<Byte>^ target3 = { 0xBB,0xAA,0xE8,0xCA,0xFD,0xFF,0xFF,0x83,0xC4,0x08 };
int matched1 = 0;
int matched2 = 0;
int matched3 = 0;
FileStream^ fs2 = gcnew FileStream(line, FileMode::Open, FileAccess::Read, FileShare::ReadWrite);
int value;
do
{
value = fs2->ReadByte();
if (value == target1[matched1]) {
matched1++;
}
else
matched1 = 0;
if (value == target2[matched2]) {
matched2++;
}
else
matched2 = 0;
if (value == target3[matched3]) {
matched3++;
}
else
matched3 = 0;
if(matched1 == target1->Length)
{
listBox1->Items->Add(line + "1");
}
if(matched2 == target2->Length)
{
listBox1->Items->Add(line + "2");
}
if(matched3 == target3->Length)
{
listBox1->Items->Add(line + "3");
}
} while (value != -1);
fs2->Close();
the problem is that it only adds line + 3 to the list box and not line + 1 or line + 2 to the list box
I do not know why that is because all 3 of the strings are in the file so they all should be added to the list box. for some reason only the last one is being added because I tried just having 2 and the second one got added.can someone show me why they are not all being added to the list box.
thanks
Update1
after playing around with it some more it is not the last target that gets added each time, It is the first string that appears in the file that gets added. I stepped through the program using message boxes and what is happening is lets say 54AAE8CAFDFFFF83C408 is the first string to appear in the file then line + 2 will be added, but then for some reason the matched integer for all 3 stop counting they just = 0 the rest of the file. can someone explain to me why that is and how to fix it.
Update2
here is the answer to the problem. all I needed to do was just add a matched = 0; after each add to list box command.
listBox1->Items->Add(line + "1");
matched1 = 0;
listBox1->Items->Add(line + "2");
matched2 = 0;
listBox1->Items->Add(line + "3");
matched3 = 0;
It seems to me that after the first matching of one pattern (here target3) you read beyond last byte of target3 (because of matched3++), this may cause undesired behavior.
Update1:
if(matched1 == target1->Length)
{
matched1 = 0; // pattern matched so reset counter
...
}
I am asking for advice and opition as of the code to use with groovy templates.
All template examples on the web used a very limited logic but I simply cannot overcome that barrier and the code in my template is substantial.
Is this acceptable? What could be a better way to do this?
Thanks
Peter
The task is to generate TCL type code - specifically if then/elsif/else type contraint
if { [streq $pm_enrichment('a1') "'aaaa2'"] && [strlen $pm_enrichment('aaaa3')] &&\
[strlen $pm_enrichment('aaaa4') ] } {
set pm_enrichment('ResultAAA') 0
}
elseif { [streq $pm_enrichment('b1') "'bb2'"] && [strlen $pm_enrichment('bbb3')] &&\
[strlen $pm_enrichment('bbbb4') ] } {
set pm_enrichment('ResultBBB') 1
}
else { [streq $pm_enrichment('c1') "'cc2'"] && [strlen $pm_enrichment('ccc3')] &&\
[strlen $pm_enrichment('cccc4') ] } {
set pm_enrichment('ResultCCC') 2G
}
//////////////////////////////////////
def dataCasesClosure= {->
pos=0
arrSorted = []
mapStmt.each{arrSorted.add(it.key) }
arrSorted = arrSorted.sort()
outStr=''''''
arrSorted.each { i ->
tmpStatement = statement
tmpResultStmt = resultStmt
list=mapStmt[i]
resultList=mapResultStmt[i]
pos=0
int index = tmpStatement.indexOf(keyword);
while (index >=0){
val = list[pos].replaceAll(~'"','')
pos +=1
tmpStatement=tmpStatement.replaceFirst( ~/#/,/${val}/)
index = tmpStatement.indexOf(keyword, index+keyword.length()) ;
}
if (tmpStatement ==~/\W+$/) {
tmpStatement=tmpStatement[0..-2]
}
pos=0
index = tmpResultStmt.indexOf(keyword);
while (index >=0){
val = resultList[pos]
pos +=1
tmpResultStmt=tmpResultStmt.replaceFirst( ~/#/,/${val}/)
index = tmpResultStmt.indexOf(keyword, index+keyword.length()) ;
}
if (i==0) {
outStr= "if {${tmpStatement} } { \n\t\t ${tmpResultStmt} \n }"
} else if (i < arrSorted.size()-1 ){
outStr += "elseif {${tmpStatement} } { \n\t\t ${tmpResultStmt} \n }"
} else {
outStr += "else {${tmpStatement} } { \n\t\t ${tmpResultStmt} \n }"
}
}
outStr
} // ### dataCasesClosure
def valuesIfThenStmt= [
"statement":dataCasesClosure
]
tplIfThenStmt = '''
##############################
${statement}
'''
def engine = new SimpleTemplateEngine()
templateResult = engine.createTemplate(tplIfThenStmt).make(valuesIfThenStmt)
println templateResult.toString()
If this is all you have to generate, the template is overkill. You could have just called the dataCasesClosure directly to get its output.
Assuming it is part of a larger template then, I think it is very reasonable to use closures to produce output for a particularly complex parts, just as you have done. I have personally done this on an extreme scale with good results.