Take the 2-minute tour ×
Graphic Design Stack Exchange is a question and answer site for Graphic Design professionals, students, and enthusiasts. It's 100% free, no registration required.

InDesign GREP rules can get a bit mind-bending. Suppose you want a paragraph style with a GREP style rule that applies a character style to everything except text after a certain character. Something that doesn't apply to characters after a certain character, but applies to everything else?

For example, imagine a long list of article titles. Some are short titles, some are two parts with a short title then a colon then an elaboration. You want the whole of the short title ones to be emphasised, and everything up to and including the colon to be emphasised in the long ones:

  • Adders of Angola
  • Brilliant Badgers: the brawniest beasts of Britain
  • Caravanning Crazes of Coastal Canadian carp
  • Danger: the dastardly ducks of Denmark

I've tried a bunch of rules but none seem to work for this. I thought it might be possible using a 'negative lookbehind', like (?<!:.*). or something, but nothing like that seems to work: it looks as if 'lookbehinds' and 'lookaheads' can only apply to the character immediately before the character you're looking for.

Any GREP experts got any ideas?


Here's one thing I figured out after a lot of browsing and trial and error, which I think logically should work, but doesn't work, for reasons I can't figure out:

\<[^:]*|\<[^:]*:

In theory, that should mean "Grab everything from the paragraph start until the end of the first run of characters that aren't ':', or, if there's a run of characters that aren't ':' from paragraph start until a ':', grab that including the ':'".

In practice, it just applies to everything. Can't figure out why.

share|improve this question

6 Answers 6

up vote 1 down vote accepted

I don't have InDesign to check this, but assuming it behaves the same as the tester here, I believe this should work:

^.*?(:|$)

That's just matching everything from the start of a string up to either the first colon or the end of the string.

share|improve this answer
    
Works perfectly! Didn't occur to me that you could use the 'or' bar within the subexpression brackets like that. I'm trying to understand the role of the question mark: is that to make it choose whichever is shorter of the possible matches? –  user568458 Apr 26 '13 at 13:31
    
Great! The question mark is exactly that. It makes the * repetition "non greedy" or "lazy" (see here), so it finds the match with the fewest repetitions instead of the most. –  David Mear Apr 26 '13 at 14:58

This is the closest I've managed:

\<[^:]*|[^:]*:

It means:

  • \<[^:]* - from the start of the paragraph (\<), grab things that aren't colons ([^:]), and grab any number of them (*)... (this gets lines that have no colons, and lines with colons up to the first colon)
  • | or...
  • [^:]*: grab any number of things that aren't colons ([^:]*) that are followed by one colon (:) (this extends the selection on lines with a colon to include the colon itself)

It works fine, unless there are two colons, in which case it applies to everything up to the last colon, not everything up to the first colon:

  • Just Annoying: why I'll never be :-D about emoticons

It doesn't stop at the first character as intended. But, it can be used if there's not going to be a second occurrence of the 'stop' character.


Bizarrely, \<[^:]* on its own, or \<[^:]*|:, seem to just grab everything. Can't figure out why.

share|improve this answer

I'd cheat (but I do that a lot).

Make sure every line ends in a colon, even the short titles which have no subtitles.

Use your GREP to make everything up to the colon bold.

Run a second S/R to find everything with "colon-hard return" and make it just "hard return" (which removes colons from any line without a subtitle).

share|improve this answer

Short and simple:

^[^:]+:?

which means "everything from the start that is not a colon, optionally followed by a colon".

"Everything from the start" -- the ^ -- needs to be specified because otherwise the GREP style will be applied from the start of a paragraph up to the first colon, and then again from that colon up to the next colon; and then again and again until the end of the paragraph. Which comes down to "actually the entire paragraph, from start to end".
Each GREP expression is applied as many times as possible inside each paragraph (quite logically; if not, the default expression \d+ would only match the first set of digits in each paragraph).

".. that is not a colon .." -- the [^:]+ matches all characters except the colon itself. If there is no colon, it will match the entire paragraph.

".. optionally followed by a colon" -- the final :? is to match the colon itself when the previous part ended just before it. It is to apply the same formatting to the colon as to the previous text.

share|improve this answer
    
Also works! :) thanks –  user568458 Nov 19 at 10:30

Here's another imperfect answer. If it's just a case of making something look different, you could do the opposite of what the question asks: have everything emphasised, grab everything after the character, and apply a style that de-emphasises it.

This is pretty simple:

:.*

It starts with whatever the first character is then keeps going, so it doesn't have the problem above.

It's not a complete answer as it won't work in cases where it has to be the first part that has the style, but it will work in some cases.

share|improve this answer

You don't need GREP to do this, you can use Nested Styles.

share|improve this answer
2  
Hi Joshua, welcome to Graphic Design stack exchange. As it stands this answer is not very descriptive. Could you elaborate on how you would achieve the results using Nested Styles? –  Ryan Feb 24 at 18:40

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.