tags:

views:

93

answers:

5

Hi,

I'm trying to write a regexp which will help to find non-translated texts in html code.

Translated texts means that they are going through special tag: or through construction: ${...}

Ex. non-translated:

<h1>Hello</h1>

Translated texts are:

<h1><fmt:message key="hello" /></h1>
<button>${expression}</button>

I've written the following expression:

\<(\w+[^>])(?:.*)\>([^\s]+?)\</\1\>

It finds correct strings like:

<p>text<p>

Correctly skips

<a><fmt:message key="common.delete" /></a>

But also catches:

<li><p><fmt:message key="common.delete" /></p></li>

And I can't figure out how to add exception for ${...} strings in this expression Can anybody help me?

+1  A: 

If the format is simple as in your examples you can try this:

<(\w+)>(?:(?!<fmt:message).)+</\1>
kemp
it works better than mine, but still catches <h1><p>hi</p></h1> (here I need only nested 'p' tag) and <p><input /></p>
glaz666
A: 

I've used a simple one like this with success,

<([^>]+)[^>]*>([^<]*)</\1>

of course if there is any CDATA with '<' in those it's not going to work so well. But should do fine for simple XML.

Mike Nelson
nice, but it doesn't work for tags with attributes like <li class="something">hi</li>
glaz666
good point, edited for that
Mike Nelson
+2  A: 

If I understand you properly, you want to ensure the data inside the "tag" doesn't contain fmt:messsage or ${....}

You might be able to use a negative-lookahead in conjuction with a . to assert that the characters captured by the . are not one of those cases:

/<(\w+)[^>]*>(?:(?!<fmt:message|\$\{|<\/\1>).)*<\/\1>/i

If you want to avoid capturing any "tags" inside the tag, you can ignore the <fmt:message portion, and just use [^<] instead of a . - to match only non <

/<(\w+)[^>]*>(?:(?!\$\{)[^<])*<\/\1>/i

Added from comment If you also want to exclude "empty" tags, add another negative-lookahead - this time (?!\s*<) - ensure that the stuff inside the tag is not empty or only containing whitespace:

/<(\w+)[^>]*>(?!\s*<)(?:(?!\$\{)[^<])*<\/\1>/i
gnarf
The latter case is the best! It is not as greedy as former (doesn't match <p><a>something</a></p>, but match just <a>something</a>). The only thing I couldn't figure out how to exclude whitespaces (i.e. not match for '<p> </p>')
glaz666
Doesn't it still match `<p><a>something</a></p>`? When it reaches `<a>` it cannot tell if it's inside a tag or not.
kemp
Great! Thank you very much!
glaz666
@kemp - No, it fails to match `<p><a` (because 'a' is not a '/') so it advances forward finding `<a>something</a>` and returns its match
gnarf
Ah I see what you mean, I thought `<p><a>something</a></p>` should fail completely
kemp
A: 

Rewritten into a more formal question:

Can you match

aba

but not

aca

without catching

abcba ?

Yes.

FSM:

Start->A->B->A->Terminate

Insert abcba and run it

Start is ready for input. 
a -> MATCH, transition to A
b -> MATCH, transition to B
c -> FAIL, return fail.
Paul Nathan
A: 

also see

http://www.codinghorror.com/blog/archives/001311.html

for a discussion of using regex to parse html

executive summary: dont

pm100