views:

127

answers:

3

Edit: To be clear, please understand that I am not using Regex to parse the html, that's crazy talk! I'm simply wanting to clean up a messy string of html so it will parse

Edit #2: I should also point out that the control character I'm using is a special unicode character - it's not something that would ever be used in a proper tag under any normal circumstances

Suppose I have a string of html that contains a bunch of control characters and I want to remove the control characters from inside tags only, leaving the characters outside the tags alone.

For example

Here the control character is the numeral "1".

Input

The quick 1<strong>orange</strong> lemming <sp11a1n 1class1='jumpe111r'11>jumps over</span> 1the idle 1frog

Desired Output

The quick 1<strong>orange</strong> lemming <span class='jumper'>jumps over</span> 1the idle 1frog

So far I can match tags which contain the control character but I can't remove them in one regex. I guess I could perform another regex on my matches, but I'd really like to know if there's a better way.

My regex

Bear in mind this one only matches tags which contain the control character.

<(([^>])*?`([^>])*?)*?>

Thanks very much for your time and consideration.

Iain Fraser

+1  A: 

Regex isn't the tool for this, but you can use lookbehind and lookahead to match 1 in a tag. Here it is in Java, modified to have finite lookbehind (since Java doesn't support infinite length lookbehind).

    String s = "123 <o123o></o1o1> <oo 11='11x'> x11 <msg136='I <3 Johnny!11'>";
    System.out.println(
        s.replaceAll("(?<=<[^<>]{0,999})(?=[^<>]+>)1", "")
    ); // prints "123 <o23o></oo> <oo ='x'> x11 <msg136='I <3 Johnny!'>

There are many cases where this will fail, but it should get you started somewhere.

See also


Okay, I've "generalized" the problem so that it's not HTML related. Here's a snippet of Java that uses regex to remove [aeiou] from portions of a sentence enclosed by < and >, whose usage is reserved only to mark these special portions.

BEWARE: this regex is absolutely unreadable. But yes, it works. And it uses no lookbehind, too.

String s = "Wait <whaaat?> does this <really really> work???";
System.out.println(
    s.replaceAll("(?!>)(?:(?=<)|(?=\\G)(?!^))(?:(?:(?![aeiou])(.))|.)", "$1")
); // prints "Wait <wht?> does this <rlly rlly> work???"

I might try to explain it if there's interest, but otherwise I'd suggesting using a simple loop like this instead:

allocate output buffer
set isInside := false
for every character ch in input
   if (ch is openChar)
      isInside := true
   else if (ch is closeChar)
      isInside := false
   else if not (isInside and ch is control)
      append ch to buffer
polygenelubricants
Just out of interest, what in your opinion would the right tool be? I'm only using Regex because there's a pretty well defined pattern to what I'm trying to remove: i.e. "Remove all control characters from within angle brackets". I should also point out, my actual control character is not something that would appear in any valid html tag.
Iain Fraser
@Iain: if you can guarantee that there will never be `<` or `>` in attribute values, then regex is okay, I think. Otherwise you'll have trouble balancing quotes, handling escape sequences, etc, and I think it'll get dicey. If `<` and `>` is reserved for opening and closing tags only, then this is trivial.
polygenelubricants
Thanks for the advice polygenelubricants - your original regex worked perfectly by the way. My reluctance to use a parsing engine comes from the fact that you might not get valid starting and ending tags - they could be inconsistant. This is possible for example: `<1strong>Hey, I1'm in bold!</strong>`
Iain Fraser
+1  A: 

You shouldn't generally use regex to parse html - but this is not html to begin with and hence you can't use a parser. The following seems to work.

var s = "The quick 1<strong>orange</strong> lemming <sp11a1n 1class1='jumpe111r'11>jumps over</span> 1the idle 1frog";
while(s.match(/<[^>]*?1(?=[^>]*>)/))
  s = s.replace(/(<[^>]*?)1(?=[^>]*>)/g, "$1");
console.log(s); //"The quick 1<strong>orange</strong> lemming <span class='jumper'>jumps over</span> 1the idle 1frog"
Amarghosh
Thanks for understanding Amarghosh - the idea is that I want to clean up a string so that it has a reasonable chance of parsing as html...
Iain Fraser
A: 

I get that you're not "parsing" it as such. You do however need to work out what is html tags and what isn't, this requires parsing and using a regex alone will not manage this.

Maybe the solution to the control chars in tag names is to replace globally all the control chars with a valid text pattern.

Then you can parse the resulting xml/html with an xml/html document parser. You can then run through this to perform your search and replaces on tagnames, attribute names, values.

Robin Day