i'd like to remove some specific css rules (i.e. width and height) out of inline style attributes.
so i want to transform the following:
<table id="foo" style="border:1px #000 solid; width: 100px; height: 100px;">
into
<table id="foo" style="border:1px #000 solid">
is there a handy regex that solves my problem?
thank you all in advance
Maybe try this (tested in Vim and Ruby):
/(width|height):\s*\d+(px|%);?//
Of course you should use your editor's (or language's) syntax for regexps (for example in Vim you have to prepend backslash before '(','|',')' and '+'
Enable regex search in your editor and try:
width="[^"]*"
height="[^"]*"
Your question is not very specific, but how about /[\s;"']width: .+;/. You need to feed that to a replace function or something, but I can't help you there because I don't know what language you're in.
Beware: regular expressions cannot correctly parse HTML.
Use a parser instead.
#! /usr/bin/perl
use warnings;
use strict;
use HTML::Parser;
die "Usage: $0 html-file\n" unless #ARGV == 1;
sub start {
my($tag,$attr,$attrseq,$text,$skipped) = #_;
print $skipped;
unless ($attr->{style} && $attr->{style} =~ /width|height/) {
print $text;
return;
}
my %style = $attr->{style} =~ /
\s* # optional leading space
(.+?) : # property, e.g., width
\s* # optional separating space
([^;]+) # value, e.g., 100px
;? # optional separator
/gx;
delete #style{qw/ width height /};
$attr->{style} = join "; " =>
map "$_: $style{$_}",
keys %style;
print "<$tag ",
join(" " => map qq[$_="$attr->{$_}"], #$attrseq),
">";
}
my $p = HTML::Parser->new(
api_version => 3,
marked_sections => 1,
start_h => [ \&start => "tag, attr, attrseq, text, skipped_text" ],
end_h => [ sub { print #_ } => "skipped_text, text" ],
);
undef $/;
$p->parse(<>);
No, you generally cannot do all that in a regular expression, because HTML is not a regular language.
Use an HTML parser to get at the style attribute from table tags, then use the regular expressions width:.+?(;|$) and height:.+?(;|$).
Related
It is necessary to perform a search and replace strings in css file. And found only the title picture with.
While the search is done so with the exception of
/:(\s*)url\(((.(?!.*https:|.*http:|.*base64|.*data:image))*)\)/ig
and replace
:$1url(\'../dist/img/vendor/$2\')
In this case, I replace the path in a similar way. And I get this result
background-image: url('../dist/img/vendor/"../images/preloader.gif"');
A need of a string
background-image: url("../images/preloader.gif");
get
background-image: url('../dist/img/vendor/preloader.gif');
Find
/(url\(\s*[\"\'])(?:[^\"\']+\/)?([^\/\"\']+[\"\']\s*\))/ig
Replace
$1../dist/img/vendor/$2
Demo https://regex101.com/r/kU7cC9/3
Using a css parser is a better way if you want among other things to avoid quotes problems (single quotes, double quotes, no quotes).
As an aside, the background-image CSS property isn't the only one that can contain a path to an image file, since the background property can compile all the data from other background- properties.
An example with sabberworm PHP CSS Parser that automatically encloses paths between double quotes:
require __DIR__ . '/vendor/autoload.php';
define('NEW_PATH', '../dist/img/vendor/');
$oCssParser = new Sabberworm\CSS\Parser($css);
$oCssDocument = $oCssParser->parse();
$properties = ['background-image', 'background'];
foreach($oCssDocument->getAllRuleSets() as $oRuleSet) {
foreach($properties as $property) {
$oCssRules = $oRuleSet->getRules($property);
foreach ($oCssRules as $oCssRule) {
$value = $oCssRule->getValue()->__toString();
if (!preg_match('~https?:|base64|data:image~S', $value)) {
$value = preg_replace('~url\("\K(?:[^"/]*/)*~', NEW_PATH, $value);
$oCssRule->setValue($value);
}
}
}
}
echo $oCssDocument->render(Sabberworm\CSS\OutputFormat::createPretty());
Can you strip carriage returns from CSS files safely?
I have an PHP example in in this case, but the question is for any programming language.
Given the following sequence of tasks in minifying CSS.
START prepare CSS
# removeComments( $this->rawCSS );
# trimLines( $css );
# stripSpaces( $css );
$css = str_replace( array( "\r\n", "\r", "\n", "\t" ) , '' , $css );
# removeDoubleSpaces( $css );
# removePunctuationSpaces( $css );
# enforceInternetExplorerLineLengthLimit( $css );
# migrateImportsToTop( $css );
DONE prepare CSS
Will the removal of characters HT (9), LF (10), FF (12), CR (13) ever leave the CSS in an invalid condition?
Lists of values for properties are often separated by white space, which can be a new line. Given this code:
div { border: solid
red
1px;
}
<div>content</div>
… stripping new lines would result in:
border: solidred1px;
… which would be invalid.
Yes, removing line breaks/tabs could make CSS invalid.
An example:
#import
url("imported.css");
would become invalid:
#importurl("imported.css");
EDIT: you can surely change the meaning of some property:
.someClass::after{
content: 'Some content here';
}
if the words are separated by TAB HT (9) you will end up with
content: 'Somecontenthere';
It can also broke some rule i think
.someClass
A{
color:white
}
it's perfectly valid css but it will end up as
.someClassA{color:white}
which is a different rule.
Yes, because of some comments.
// This is my precious class
.preciousClass {
color: yellow;
}
When you remove all whitespace, though, this happens. It's not syntactically invalid, but it is not working any longer.
// This is my precious class.preciousClass { color: yellow;}
But otherwise, your CSS won't be invalid just by removing non-space whitespace.
I'm trying to write regexp to find all rules in CSS filest that don't have semicolon at the end:
.abc {
height: 100%;
margin: auto;
text-align: center /* <-- like this one */
width: 100%;
}
i've tried this [^;\{\}]\n but it not excluding { and } from search. Any ideas?
What you need is a CSS parser.
However, if this is a one-off job, and your regex engine supports lookbehinds, you can use this regex:
^.*(?<![;{}])$
Visualization:
(?<![;{}]) is a negative lookbehind that asserts that the line should end with a character that's not ;, { or }.
Note that the regex is far from perfect and fails to match properly if a CSS block is used by more than one class/id or if every class/id is separated by a line break.
RegEx Demo
In perl you can easily do this,
e.g:
#!/usr/bin/perl
# open your file
open(FILE,"filename.css");
my #fileLines = <FILE>;
close FILE;
my $lineCount=1;
# check all lines of your file
foreach my $line(#fileLines){
# erase endline spaces
$line=~ s/\s+$//;
# erase begin of line
$line=~ s/^\s+//;
# simple perl regex, it doesn't watch for comments
if($line !~ /\;$/ && $line !~ /{$/ && $line !~/}$/){
print $lineCount.':'.$line.'\n';
}
$lineCount++;
}
This small program will show you lines which not finnish by ';'.
You could just run the file through http://csslint.net
I ned some help with RegEx, not sure what I am doing wrong.
What I would like to achieve is to change the value of one CSS property in a CSS file without altering anything within that CSS file.
<?php
$var = '
#css {
text-size: 14px;
color: red;
background: orange;
}
';
echo preg_replace('/#css(.*)color: (.*);(.*)}/is','#css$1color: black;$3 }',$var);
?>
The result I am hoping to see is this:
#css {
text-size: 14px;
color: red;
background: orange;
}
However what I get is this:
#css {
text-size: 14px;
color: black;
}
I am not an expert in RegEx at all but after reading manuals and examples online I thought I could use backreferences to do this and that $1 would be the result of the first match, $2 of the second, $3 of the third etc... In my example $1 matches everything between '#css' and 'color: ' and then $2 I don't use because I want to replace 'red' with 'black'. I thought $3 would be the result of everything between ';' and '}' but it gets lost somewhere or, more likely, I am lost somewhere ;-)
Thanks for the advice and support.
First of all, using the greedy .* is always problematic. In your case, it cosumes too much symbols so that you lose the background because it matches the last ; in your code (which comes after the background declaration). Instead use a negative character class which matches until the very next symbol you know should not be included in the match - in your case the ;. So the character class should look like: [^;]*. The same is true with matching the } symbol - use a negative character class instead.
Secondly, I would try to reduce the usage of capture groups.
And finally, I would reduce the clutter and put everything you don't want to replace into the capturegroups before and after so that you get a very simple result: '$1black$2'
Try the following regex:
preg_replace('/(#css.*?color:)[^;]*([^}]*)/is','$1black$2',$var);
See the demo
Note that this regex has one flaw: If you have different colors in your decplarations (background-color, border-color,...), it will break! So you should include an additional whitespace to make sure it only captures the "real" color declaration:
/(#css.*?\scolor:)[^;]*([^}]*)/is
This still might break if (which should not happen) per accident you have multiple color:xyz; declarations in your rule block. Only the first one gets replace then.
The problem here is that you're matching greedily for your second capture group. In doing so, it consumes everything up until the final semicolon in your text.
What you should be doing instead is using a lazy matching group instead which will match as few characters as possible. (eg. only up until the first semicolon, rather than the last)
preg_replace('/#css(.*)color: .*?;(.*)}/is','#css$1color: black;$2 }',$var);
As I understand your problem, I think this will solve your issue.
$var = '
#css {
text-size: 14px;
color: red;
background: orange;
}
';
preg_match_all('/(#css\s*\{[\sA-z0-9#:;-]*color\s*:\s*[A-z0-9#]*)/', $var, $output);
$temp = preg_replace('/(color\s*:\s*[A-z0-9#]*)/im', 'color: black', $output[0][0]);
echo preg_replace('/(#css\s*\{[\sA-z0-9#:;-]*color\s*:\s*[A-z0-9#]*)/im', $temp, $var);
?>
Here is my HTML:
small caps &
ALL CAPS
Here is my CSS:
.link {text-transform: capitalize;}
The output is:
Small Caps & ALL CAPS
and I want the output to be:
Small Caps & All Caps
Any ideas?
You can almost do it with:
.link {
text-transform: lowercase;
}
.link:first-letter,
.link:first-line {
text-transform: uppercase;
}
It will give you the output:
Small Caps
All Caps
There is no way to do this with CSS, you could use PHP or Javascript for this.
PHP example:
$text = "ALL CAPS";
$text = ucwords(strtolower($text)); // All Caps
jQuery example (it's a plugin now!):
// Uppercase every first letter of a word
jQuery.fn.ucwords = function() {
return this.each(function(){
var val = $(this).text(), newVal = '';
val = val.split(' ');
for(var c=0; c < val.length; c++) {
newVal += val[c].substring(0,1).toUpperCase() + val[c].substring(1,val[c].length) + (c+1==val.length ? '' : ' ');
}
$(this).text(newVal);
});
}
$('a.link').ucwords();
Convert with JavaScript using .toLowerCase() and capitalize would do the rest.
Interesting question!
capitalize transforms every first letter of a word to uppercase, but it does not transform the other letters to lowercase. Not even the :first-letter pseudo-class will cut it (because it applies to the first letter of each element, not each word), and I can't see a way of combining lowercase and capitalize to get the desired outcome.
So as far as I can see, this is indeed impossible to do with CSS.
#Harmen shows good-looking PHP and jQuery workarounds in his answer.
I'd like to sugest a pure CSS solution that is more useful than the first letter solution presented but is also very similar.
.link {
text-transform: lowercase;
display: inline-block;
}
.link::first-line {
text-transform: capitalize;
}
<div class="link">HELLO WORLD!</div>
<p class="link">HELLO WORLD!</p>
HELLO WORLD! ( now working! )
Although this is limited to the first line it may be useful for more use cases than the first letter solution since it applies capitalization to the whole line and not only the first word. (all words in the first line)
In the OP's specific case this could have solved it.
Notes: As mentioned in the first letter solution comments, the order of the CSS rules is important! Also note that I changed the <a> tag for a <div> tag because for some reason the pseudo-element ::first-line doesn't work with <a> tags natively but either <div> or <p> are fine.
EDIT: the <a> element will work if display: inline-block; is added to the .link class. Thanks to Dave Land for spotting that!
New Note: if the text wraps it will loose the capitalization because it is now in fact on the second line (first line is still ok).
JavaScript:
var links = document.getElementsByClassName("link");
for (var i = 0; i < links.length; i++) {
links[i].innerHTML = links[i].innerHTML.toLowerCase();
}
CSS:
.link { text-transform: capitalize; }
What Khan "ended up doing" (which is cleaner and worked for me) is down in the comments of the post marked as the answer.
captialize only effects the first letter of the word. http://www.w3.org/TR/CSS21/text.html#propdef-text-transform
You can do it with css first-letter!
eg I wanted it for the Menu:
a {display:inline-block; text-transorm:uppercase;}
a::first-letter {font-size:50px;}
It only runs with block elements - therefore the inline-block!
May be useful for java and jstl.
Initialize variable with localized message.
After that it is possible to use it in jstl toLowerCase function.
Transform with CSS.
In JSP
1.
<fmt:message key="some.key" var="item"/>
2.
<div class="content">
${fn:toLowerCase(item)}
</div>
In CSS
3.
.content {
text-transform:capitalize;
}
If the data is coming from a database, as in my case, you can lower it before sending it to a select list/drop down list. Shame you can't do it in CSS.
After researching a lot I found jquery function/expression to change text in first letter in uppercase only, I modify that code accordingly to make it workable for input field. When you will write something in input field and then move to another filed or element, the text of that field will change with 1st-letter capitalization only. No matter user type text in complete lower or upper case capitalization:
Follow this code:
Step-1: Call jquery library in html head:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
Step-2: Write code to change text of input fields:
<script>
$(document).ready(function(){
$("#edit-submitted-first-name,#edit-submitted-last-name,#edit-submitted-company-name, #edit-submitted-city").focusout(function(){
var str=$(this).val();
str = str.toLowerCase().replace(/\b[a-z]/g, function(letter) {
return letter.toUpperCase();
});
$(this).val(str);
});});
</script>
Step-3: Create HTML input fields with same id's you use in jquery code like:
<input type="text" id="edit-submitted-first-name" name="field name">
The id of this input field is: edit-submitted-first-name (It using in jquery code in step-2)
**Result:
Make sure the text will change after you move your focus from that input field at another element. Because we using focus out event of jquery here.
Result should like this: User Type: "thank you" it will change with "Thank You".
**
Best of luck
The PHP solution, in backend:
$string = 'UPPERCASE';
$lowercase = strtolower($string);
echo ucwords($lowercase);
I know this is a late response but if you want to compare the performance of various solutions I have a jsPerf that I created.
Regex solutions are the fastest for sure.
Here is the jsPerf: https://jsperf.com/capitalize-jwaz
There are 2 regex solutions.
The first one uses/\b[a-z]/g. Word boundary will capital words such as non-disclosure to Non-Disclosure.
If you only want to capitalize letters that are preceded by a space then use the second regex
/(^[a-z]|\s[a-z])/g
if you are using jQuery; this is one a way to do it:
$('.link').each(function() {
$(this).css('text-transform','capitalize').text($(this).text().toLowerCase());
});
Here is an easier to read version doing the same thing:
//Iterate all the elements in jQuery object
$('.link').each(function() {
//get text from element and make it lower-case
var string = $(this).text().toLowerCase();
//set element text to the new string that is lower-case
$(this).text(string);
//set the css to capitalize
$(this).css('text-transform','capitalize');
});
Demo
all wrong it does exist --> font-variant: small-caps;
text-transform:capitalize; just the first letter cap