Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
View | Details | Raw Unified | Return to bug 80667 | Differences between
and this patch

Collapse All | Expand All

(-)reference/ref-regex-find-replace.htm (-6 / +32 lines)
Lines 5-11 Link Here
5
   <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
5
   <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
6
   <meta http-equiv="Content-Style-Type" content="text/css"><title>Find/Replace with Regular Expressions</title>
6
   <meta http-equiv="Content-Style-Type" content="text/css"><title>Find/Replace with Regular Expressions</title>
7
   
7
   
8
<script language="JavaScript" src="PLUGINS_ROOT/org.eclipse.help/livehelp.js"></script>
9
<link rel="STYLESHEET" href="../book.css" charset="ISO-8859-1" type="text/css"></head><body bgcolor="#ffffff">
8
<link rel="STYLESHEET" href="../book.css" charset="ISO-8859-1" type="text/css"></head><body bgcolor="#ffffff">
10
9
11
<h1 class="Head">Find/Replace with Regular Expressions</h1>
10
<h1 class="Head">Find/Replace with Regular Expressions</h1>
Lines 15-25 Link Here
15
</p>
14
</p>
16
15
17
<p>
16
<p>
18
The <strong>Replace</strong> field allows the following regular expressions:
17
The <strong>Replace</strong> field allows the following constructs:
19
<ul>
20
	<li>$i to match capturing group i</li>
21
	<li>- \x to quote character x</li>
22
</ul>
23
</p>
18
</p>
19
  <table border="1" cellpadding="5" summary="supported constructs in the replace field">
20
    <tbody>
21
      <tr>
22
        <td>$i</td>
23
        <td>inserts
24
          <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/regex/Pattern.html#cg">capturing group</a>
25
          i.
26
        </td>
27
      </tr>
28
      <tr>
29
        <td>\i</td>
30
        <td>inserts
31
          <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/regex/Pattern.html#cg">capturing group</a>
32
          i (same as $i).
33
        </td>
34
      </tr>
35
      
36
      <tr> <td>\<i>x</i></td> <td>quotes character <i>x</i> (unless \<i>x</i> has a special meaning)</td> </tr>
37
      <tr> <td>\R</td> <td>inserts the default line delimiter of the document</td> </tr>
38
      <tr> <td>\x<i>hh</i></td> <td>inserts the hexadecimal character <i>hh</i></td> </tr>
39
      <tr> <td>\u<i>hhhh</i></td> <td>inserts the Unicode character <i>hhhh</i></td> </tr>
40
      <tr> <td>\n</td> <td>inserts a newline character (usually, you should use \R instead)</td> </tr>
41
      <tr> <td>\r</td> <td>inserts a carriage-return character (usually, you should use \R instead)</td> </tr>
42
      <tr> <td>\t</td> <td>inserts a tab character</td> </tr>
43
      <tr> <td>\f</td> <td>inserts a form-feed character</td> </tr>
44
      <tr> <td>\a</td> <td>inserts an alert (beep) character</td> </tr>
45
      <tr> <td>\e</td> <td>inserts an escape character</td> </tr>
46
      <tr> <td>\c<i>C</i></td> <td>inserts a the control character for <i>C</i></td> </tr>
47
      
48
    </tbody>
49
  </table>
24
50
25
</body></html>
51
</body></html>
(-)src/org/eclipse/ui/texteditor/RegExMessages.java (-7 / +13 lines)
Lines 48-53 Link Here
48
	public static String additionalInfo_bs_n;
48
	public static String additionalInfo_bs_n;
49
	public static String displayString_bs_r;
49
	public static String displayString_bs_r;
50
	public static String additionalInfo_bs_r;
50
	public static String additionalInfo_bs_r;
51
	public static String displayString_bs_rnWU;
52
	public static String additionalInfo_bs_rnWU;
53
	public static String displayString_bs_rn;
54
	public static String additionalInfo_bs_rn;
51
	public static String displayString_bs_f;
55
	public static String displayString_bs_f;
52
	public static String additionalInfo_bs_f;
56
	public static String additionalInfo_bs_f;
53
	public static String displayString_bs_a;
57
	public static String displayString_bs_a;
Lines 189-200 Link Here
189
	//replace
193
	//replace
190
	public static String displayString_dollar;
194
	public static String displayString_dollar;
191
	public static String additionalInfo_dollar;
195
	public static String additionalInfo_dollar;
192
	public static String additionalInfo_replace_bs;
196
	public static String displayString_replace_cap;
197
	public static String additionalInfo_replace_cap;
193
	public static String displayString_replace_bs;
198
	public static String displayString_replace_bs;
194
	public static String displayString_tab;
199
	public static String additionalInfo_replace_bs;
195
	public static String additionalInfo_tab;
200
	public static String displayString_replace_bs_n;
196
	public static String displayString_nl;
201
	public static String additionalInfo_replace_bs_n;
197
	public static String additionalInfo_nl;
202
	public static String displayString_replace_bs_r;
198
	public static String displayString_cr;
203
	public static String additionalInfo_replace_bs_r;
199
	public static String additionalInfo_cr;
204
	public static String displayString_replace_bs_R;
205
	public static String additionalInfo_replace_bs_R;
200
}
206
}
(-)src/org/eclipse/ui/texteditor/FindNextAction.java (-17 / +14 lines)
Lines 124-135 Link Here
124
	 * @return the find string
124
	 * @return the find string
125
	 */
125
	 */
126
	private String getFindString() {
126
	private String getFindString() {
127
		String string= getSelectionString();
127
		String fullSelection= fTarget.getSelectionText();
128
128
		String firstLine= getFirstLine(fullSelection);
129
		if ((string == null || fRegExSearch && string.equals(fSelection)) && !fFindHistory.isEmpty())
129
		if ((firstLine.length() == 0 || fRegExSearch && fullSelection.equals(fSelection)) && !fFindHistory.isEmpty())
130
			string= (String) fFindHistory.get(0);
130
			return (String) fFindHistory.get(0);
131
131
		else if (fRegExSearch && fullSelection.length() > 0)
132
		return string;
132
			return FindReplaceDialog.escapeForRegExPattern(fullSelection);
133
		else
134
			return firstLine;
133
	}
135
	}
134
136
135
	/**
137
	/**
Lines 385-401 Link Here
385
	}
387
	}
386
388
387
	/**
389
	/**
388
	 * Returns the actual selection of the find replace target.
390
	 * Returns the first line of the given selection.
389
	 *
391
	 * 
390
	 * @return the actual selection of the find replace target
392
	 * @param selection the selection
393
	 * @return the first line of the selection
391
	 */
394
	 */
392
	private String getSelectionString() {
395
	private String getFirstLine(String selection) {
393
394
		/*
395
		 * 1GF86V3: ITPUI:WINNT - Internal errors using Find/Replace Dialog
396
		 * Now uses TextUtilities rather than focusing on '\n'
397
		 */
398
		String selection= fTarget.getSelectionText();
399
		if (selection.length() > 0) {
396
		if (selection.length() > 0) {
400
			int[] info= TextUtilities.indexOf(TextUtilities.DELIMITERS, selection, 0);
397
			int[] info= TextUtilities.indexOf(TextUtilities.DELIMITERS, selection, 0);
401
			if (info[0] > 0)
398
			if (info[0] > 0)
Lines 403-408 Link Here
403
			else if (info[0] == -1)
400
			else if (info[0] == -1)
404
				return selection;
401
				return selection;
405
		}
402
		}
406
		return null;
403
		return selection;
407
	}
404
	}
408
}
405
}
(-)src/org/eclipse/ui/texteditor/RegExContentProposalProvider.java (-24 / +19 lines)
Lines 119-128 Link Here
119
			addBsProposal("\\t", RegExMessages.displayString_bs_t, RegExMessages.additionalInfo_bs_t); //$NON-NLS-1$
119
			addBsProposal("\\t", RegExMessages.displayString_bs_t, RegExMessages.additionalInfo_bs_t); //$NON-NLS-1$
120
			addBsProposal("\\n", RegExMessages.displayString_bs_n, RegExMessages.additionalInfo_bs_n); //$NON-NLS-1$
120
			addBsProposal("\\n", RegExMessages.displayString_bs_n, RegExMessages.additionalInfo_bs_n); //$NON-NLS-1$
121
			addBsProposal("\\r", RegExMessages.displayString_bs_r, RegExMessages.additionalInfo_bs_r); //$NON-NLS-1$
121
			addBsProposal("\\r", RegExMessages.displayString_bs_r, RegExMessages.additionalInfo_bs_r); //$NON-NLS-1$
122
			addBracketProposal("\\r?\\n", 5, RegExMessages.displayString_bs_rnWU, RegExMessages.additionalInfo_bs_rnWU); //$NON-NLS-1$
123
			addBracketProposal("(\\r\\n?|\\n)", 10, RegExMessages.displayString_bs_rn, RegExMessages.additionalInfo_bs_rn); //$NON-NLS-1$
122
			addBsProposal("\\f", RegExMessages.displayString_bs_f, RegExMessages.additionalInfo_bs_f); //$NON-NLS-1$
124
			addBsProposal("\\f", RegExMessages.displayString_bs_f, RegExMessages.additionalInfo_bs_f); //$NON-NLS-1$
123
			addBsProposal("\\a", RegExMessages.displayString_bs_a, RegExMessages.additionalInfo_bs_a); //$NON-NLS-1$
125
			addBsProposal("\\a", RegExMessages.displayString_bs_a, RegExMessages.additionalInfo_bs_a); //$NON-NLS-1$
124
			addBsProposal("\\e", RegExMessages.displayString_bs_e, RegExMessages.additionalInfo_bs_e); //$NON-NLS-1$
126
			addBsProposal("\\e", RegExMessages.displayString_bs_e, RegExMessages.additionalInfo_bs_e); //$NON-NLS-1$
125
			addBsProposal("\\c", RegExMessages.displayString_bs_c, RegExMessages.additionalInfo_bs_c); //$NON-NLS-1$
127
			addBracketProposal("\\c", 2, RegExMessages.displayString_bs_c, RegExMessages.additionalInfo_bs_c); //$NON-NLS-1$
126
			
128
			
127
			if (! fIsEscape)
129
			if (! fIsEscape)
128
				addBracketProposal(".", 1, RegExMessages.displayString_dot, RegExMessages.additionalInfo_dot); //$NON-NLS-1$
130
				addBracketProposal(".", 1, RegExMessages.displayString_dot, RegExMessages.additionalInfo_dot); //$NON-NLS-1$
Lines 156-180 Link Here
156
				addBracketProposal("\\P{}", 3, RegExMessages.displayString_posixNot, RegExMessages.additionalInfo_posixNot); //$NON-NLS-1$
158
				addBracketProposal("\\P{}", 3, RegExMessages.displayString_posixNot, RegExMessages.additionalInfo_posixNot); //$NON-NLS-1$
157
			}
159
			}
158
			
160
			
159
//			addBsProposal("\\p{Lower}", RegExMessages.displayString_bs_p{Lower}, RegExMessages.additionalInfo_bs_p{Lower}); //$NON-NLS-1$
160
//			addBsProposal("\\p{Upper}", RegExMessages.displayString_bs_p{Upper}, RegExMessages.additionalInfo_bs_p{Upper}); //$NON-NLS-1$
161
//			addBsProposal("\\p{ASCII}", RegExMessages.displayString_bs_p{ASCII}, RegExMessages.additionalInfo_bs_p{ASCII}); //$NON-NLS-1$
162
//			addBsProposal("\\p{Alpha}", RegExMessages.displayString_bs_p{Alpha}, RegExMessages.additionalInfo_bs_p{Alpha}); //$NON-NLS-1$
163
//			addBsProposal("\\p{Digit}", RegExMessages.displayString_bs_p{Digit}, RegExMessages.additionalInfo_bs_p{Digit}); //$NON-NLS-1$
164
//			addBsProposal("\\p{Alnum}", RegExMessages.displayString_bs_p{Alnum}, RegExMessages.additionalInfo_bs_p{Alnum}); //$NON-NLS-1$
165
//			addBsProposal("\\p{Punct}", RegExMessages.displayString_bs_p{Punct}, RegExMessages.additionalInfo_bs_p{Punct}); //$NON-NLS-1$
166
//			addBsProposal("\\p{Graph}", RegExMessages.displayString_bs_p{Graph}, RegExMessages.additionalInfo_bs_p{Graph}); //$NON-NLS-1$
167
//			addBsProposal("\\p{Print}", RegExMessages.displayString_bs_p{Print}, RegExMessages.additionalInfo_bs_p{Print}); //$NON-NLS-1$
168
//			addBsProposal("\\p{Blank}", RegExMessages.displayString_bs_p{Blank}, RegExMessages.additionalInfo_bs_p{Blank}); //$NON-NLS-1$
169
//			addBsProposal("\\p{Cntrl}", RegExMessages.displayString_bs_p{Cntrl}, RegExMessages.additionalInfo_bs_p{Cntrl}); //$NON-NLS-1$
170
//			addBsProposal("\\p{XDigit}", RegExMessages.displayString_bs_p{XDigit}, RegExMessages.additionalInfo_bs_p{XDigit}); //$NON-NLS-1$
171
//			addBsProposal("\\p{Space}", RegExMessages.displayString_bs_p{Space}, RegExMessages.additionalInfo_bs_p{Space}); //$NON-NLS-1$
172
//
173
//			addBsProposal("\\p{InGreek}", RegExMessages.displayString_bs_p{InGreek}, RegExMessages.additionalInfo_bs_p{InGreek}); //$NON-NLS-1$
174
//			addBsProposal("\\p{Lu}", RegExMessages.displayString_bs_p{Lu}, RegExMessages.additionalInfo_bs_p{Lu}); //$NON-NLS-1$
175
//			addBsProposal("\\p{Sc}", RegExMessages.displayString_bs_p{Sc}, RegExMessages.additionalInfo_bs_p{Sc}); //$NON-NLS-1$
176
//			addBsProposal("\\P{InGreek}", RegExMessages.displayString_bs_P{InGreek}, RegExMessages.additionalInfo_bs_P{InGreek}); //$NON-NLS-1$
177
			
178
			//boundary matchers
161
			//boundary matchers
179
			if (fDocumentOffset == 0) {
162
			if (fDocumentOffset == 0) {
180
				addPriorityProposal("^", RegExMessages.displayString_start, RegExMessages.additionalInfo_start); //$NON-NLS-1$
163
				addPriorityProposal("^", RegExMessages.displayString_start, RegExMessages.additionalInfo_start); //$NON-NLS-1$
Lines 203-209 Link Here
203
				addBracketProposal("(?:)", 3, RegExMessages.displayString_nonCap, RegExMessages.additionalInfo_nonCap); //$NON-NLS-1$
186
				addBracketProposal("(?:)", 3, RegExMessages.displayString_nonCap, RegExMessages.additionalInfo_nonCap); //$NON-NLS-1$
204
				addBracketProposal("(?>)", 3, RegExMessages.displayString_atomicCap, RegExMessages.additionalInfo_atomicCap); //$NON-NLS-1$
187
				addBracketProposal("(?>)", 3, RegExMessages.displayString_atomicCap, RegExMessages.additionalInfo_atomicCap); //$NON-NLS-1$
205
				
188
				
206
				//lookaraound
189
				//look around
207
				addBracketProposal("(?=)", 3, RegExMessages.displayString_posLookahead, RegExMessages.additionalInfo_posLookahead); //$NON-NLS-1$
190
				addBracketProposal("(?=)", 3, RegExMessages.displayString_posLookahead, RegExMessages.additionalInfo_posLookahead); //$NON-NLS-1$
208
				addBracketProposal("(?!)", 3, RegExMessages.displayString_negLookahead, RegExMessages.additionalInfo_negLookahead); //$NON-NLS-1$
191
				addBracketProposal("(?!)", 3, RegExMessages.displayString_negLookahead, RegExMessages.additionalInfo_negLookahead); //$NON-NLS-1$
209
				addBracketProposal("(?<=)", 4, RegExMessages.displayString_posLookbehind, RegExMessages.additionalInfo_posLookbehind); //$NON-NLS-1$
192
				addBracketProposal("(?<=)", 4, RegExMessages.displayString_posLookbehind, RegExMessages.additionalInfo_posLookbehind); //$NON-NLS-1$
Lines 249-259 Link Here
249
			if (fDocumentOffset > 0 && '$' == fExpression.charAt(fDocumentOffset - 1)) {
232
			if (fDocumentOffset > 0 && '$' == fExpression.charAt(fDocumentOffset - 1)) {
250
				addProposal("", RegExMessages.displayString_dollar, RegExMessages.additionalInfo_dollar); //$NON-NLS-1$
233
				addProposal("", RegExMessages.displayString_dollar, RegExMessages.additionalInfo_dollar); //$NON-NLS-1$
251
			} else {
234
			} else {
252
				addProposal("$", RegExMessages.displayString_dollar, RegExMessages.additionalInfo_dollar); //$NON-NLS-1$
235
				if (! fIsEscape)
236
					addProposal("$", RegExMessages.displayString_dollar, RegExMessages.additionalInfo_dollar); //$NON-NLS-1$
237
				addBsProposal("\\", RegExMessages.displayString_replace_cap, RegExMessages.additionalInfo_replace_cap); //$NON-NLS-1$
253
				addBsProposal("\\", RegExMessages.displayString_replace_bs, RegExMessages.additionalInfo_replace_bs); //$NON-NLS-1$
238
				addBsProposal("\\", RegExMessages.displayString_replace_bs, RegExMessages.additionalInfo_replace_bs); //$NON-NLS-1$
254
				addProposal("\t", RegExMessages.displayString_tab, RegExMessages.additionalInfo_tab); //$NON-NLS-1$
239
				addBsProposal("\\R", RegExMessages.displayString_replace_bs_R, RegExMessages.additionalInfo_replace_bs_R); //$NON-NLS-1$
240
				addBracketProposal("\\x", 2, RegExMessages.displayString_bs_x, RegExMessages.additionalInfo_bs_x); //$NON-NLS-1$
241
				addBracketProposal("\\u", 2, RegExMessages.displayString_bs_u, RegExMessages.additionalInfo_bs_u); //$NON-NLS-1$
242
				addBsProposal("\\t", RegExMessages.displayString_bs_t, RegExMessages.additionalInfo_bs_t); //$NON-NLS-1$
243
				addBsProposal("\\n", RegExMessages.displayString_replace_bs_n, RegExMessages.additionalInfo_replace_bs_n); //$NON-NLS-1$
244
				addBsProposal("\\r", RegExMessages.displayString_replace_bs_r, RegExMessages.additionalInfo_replace_bs_r); //$NON-NLS-1$
245
				addBsProposal("\\f", RegExMessages.displayString_bs_f, RegExMessages.additionalInfo_bs_f); //$NON-NLS-1$
246
				addBsProposal("\\a", RegExMessages.displayString_bs_a, RegExMessages.additionalInfo_bs_a); //$NON-NLS-1$
247
				addBsProposal("\\e", RegExMessages.displayString_bs_e, RegExMessages.additionalInfo_bs_e); //$NON-NLS-1$
248
				addBracketProposal("\\c", 2, RegExMessages.displayString_bs_c, RegExMessages.additionalInfo_bs_c); //$NON-NLS-1$
255
			}
249
			}
256
			return (IContentProposal[]) fProposals.toArray(new IContentProposal[fProposals.size()]);
250
			fPriorityProposals.addAll(fProposals);
251
			return (IContentProposal[]) fPriorityProposals.toArray(new IContentProposal[fPriorityProposals.size()]);
257
		}
252
		}
258
		
253
		
259
		/**
254
		/**
(-)src/org/eclipse/ui/texteditor/FindReplaceDialog.java (-10 / +80 lines)
Lines 919-929 Link Here
919
	// ------- init / close ---------------------------------------
919
	// ------- init / close ---------------------------------------
920
920
921
	/**
921
	/**
922
	 * Returns the actual selection of the find replace target.
922
	 * Returns the first line of the given selection.
923
	 * @return the selection of the target
923
	 * 
924
	 * @param selection the selection
925
	 * @return the first line of the selection
924
	 */
926
	 */
925
	private String getSelectionString() {
927
	private String getFirstLine(String selection) {
926
		String selection= fTarget.getSelectionText();
927
		if (selection.length() > 0) {
928
		if (selection.length() > 0) {
928
			int[] info= TextUtilities.indexOf(TextUtilities.DELIMITERS, selection, 0);
929
			int[] info= TextUtilities.indexOf(TextUtilities.DELIMITERS, selection, 0);
929
			if (info[0] > 0)
930
			if (info[0] > 0)
Lines 931-937 Link Here
931
			else if (info[0] == -1)
932
			else if (info[0] == -1)
932
				return selection;
933
				return selection;
933
		}
934
		}
934
		return null;
935
		return selection;
935
	}
936
	}
936
937
937
	/**
938
	/**
Lines 978-984 Link Here
978
	private void writeSelection() {
979
	private void writeSelection() {
979
		if (fTarget == null)
980
		if (fTarget == null)
980
			return;
981
			return;
981
		
982
982
		IDialogSettings s= getDialogSettings();
983
		IDialogSettings s= getDialogSettings();
983
		s.put("selection", fTarget.getSelectionText()); //$NON-NLS-1$
984
		s.put("selection", fTarget.getSelectionText()); //$NON-NLS-1$
984
	}
985
	}
Lines 1006-1016 Link Here
1006
	 */
1007
	 */
1007
	private void initFindStringFromSelection() {
1008
	private void initFindStringFromSelection() {
1008
		if (fTarget != null && okToUse(fFindField)) {
1009
		if (fTarget != null && okToUse(fFindField)) {
1009
			String selection= getSelectionString();
1010
			String fullSelection= fTarget.getSelectionText();
1011
			String firstLine= getFirstLine(fullSelection);
1012
			boolean isRegEx= isRegExSearchAvailableAndChecked();
1010
			fFindField.removeModifyListener(fFindModifyListener);
1013
			fFindField.removeModifyListener(fFindModifyListener);
1011
			if (selection != null) {
1014
			if (firstLine.length() > 0 || (isRegEx && fullSelection.length() > 0)) {
1012
				fFindField.setText(selection);
1015
				String pattern= isRegEx ? escapeForRegExPattern(fullSelection) : firstLine;
1013
				if (!selection.equals(fTarget.getSelectionText())) {
1016
				fFindField.setText(pattern);
1017
				if (!firstLine.equals(fullSelection)) {
1018
					// multiple lines selected
1014
					useSelectedLines(true);
1019
					useSelectedLines(true);
1015
					fGlobalRadioButton.setSelection(false);
1020
					fGlobalRadioButton.setSelection(false);
1016
					fSelectedRangeRadioButton.setSelection(true);
1021
					fSelectedRangeRadioButton.setSelection(true);
Lines 1030-1035 Link Here
1030
	}
1035
	}
1031
1036
1032
	/**
1037
	/**
1038
	 * Escapes special characters in the string, such that the resulting pattern
1039
	 * matches the given string.
1040
	 * 
1041
	 * @param string the string to escape
1042
	 * @return a regex pattern that matches the given string
1043
	 */
1044
	public static String escapeForRegExPattern(String string) {
1045
		//implements https://bugs.eclipse.org/bugs/show_bug.cgi?id=44422
1046
1047
		StringBuffer pattern= new StringBuffer(string.length() + 16);
1048
		int length= string.length();
1049
		if (length > 0 && string.charAt(0) == '^')
1050
			pattern.append('\\');
1051
		for (int i= 0; i < length; i++) {
1052
			char ch= string.charAt(i);
1053
			switch (ch) {
1054
				case '\\':
1055
				case '(':
1056
				case ')':
1057
				case '[':
1058
				case ']':
1059
				case '{':
1060
				case '}':
1061
				case '.':
1062
				case '?':
1063
				case '*':
1064
				case '+':
1065
				case '|':
1066
					pattern.append('\\').append(ch);
1067
					break;
1068
					
1069
				case '\n':
1070
					pattern.append("\\n"); //$NON-NLS-1$
1071
					break;
1072
				case '\r':
1073
					pattern.append("\\r"); //$NON-NLS-1$
1074
					break;
1075
				case '\t':
1076
					pattern.append("\\t"); //$NON-NLS-1$
1077
					break;
1078
				case '\f':
1079
					pattern.append("\\f"); //$NON-NLS-1$
1080
					break;
1081
				case 0x07:
1082
					pattern.append("\\a"); //$NON-NLS-1$
1083
					break;
1084
				case 0x1B:
1085
					pattern.append("\\e"); //$NON-NLS-1$
1086
					break;
1087
1088
				default:
1089
					if (0 <= ch && ch < 0x20) {
1090
						pattern.append("\\x"); //$NON-NLS-1$
1091
						pattern.append(Integer.toHexString(ch).toUpperCase());
1092
					} else {
1093
						pattern.append(ch);
1094
					}
1095
			}
1096
		}
1097
		if (length > 0 && string.charAt(length - 1) == '$')
1098
			pattern.insert(pattern.length() - 1, '\\');
1099
		return pattern.toString();
1100
	}
1101
1102
	/**
1033
	 * Initializes the anchor used as starting point for incremental searching.
1103
	 * Initializes the anchor used as starting point for incremental searching.
1034
	 * @since 2.0
1104
	 * @since 2.0
1035
	 */
1105
	 */
(-)src/org/eclipse/ui/texteditor/RegExMessages.properties (-13 / +48 lines)
Lines 22-38 Link Here
22
displayString_bs_t= \\t - Tab
22
displayString_bs_t= \\t - Tab
23
additionalInfo_bs_t= Tabulator (\\x09, decimal: 9)
23
additionalInfo_bs_t= Tabulator (\\x09, decimal: 9)
24
displayString_bs_n= \\n - Newline
24
displayString_bs_n= \\n - Newline
25
additionalInfo_bs_n= Newline (\\x0A, decimal: 10)
25
additionalInfo_bs_n= Newline (\\x0A, decimal: 10)\n\n\
26
Note that \\n only finds newline characters. \
27
This can lead to unexpected results when the actual document uses different line delimiters.\n\n\
28
To find Windows and Unix style line delimiters, use \\r?\\n \n\
29
To find all kinds of line delimiters, use (\\r\\n?|\\n)
26
displayString_bs_r= \\r - CR
30
displayString_bs_r= \\r - CR
27
additionalInfo_bs_r= Carriage Return (\\x0D, decimal: 13)
31
additionalInfo_bs_r= Carriage Return (\\x0D, decimal: 13)\n\n\
32
Note that \\r only finds carriage return characters. \
33
This can lead to unexpected results when the actual document uses different line delimiters.\n\n\
34
To find Windows and Unix style line delimiters, use \\r?\\n \n\
35
To find all kinds of line delimiters, use (\\r\\n?|\\n)
36
displayString_bs_rnWU= \\r?\\n - Line delimiter (Windows and Unix)
37
additionalInfo_bs_rnWU= Line delimiter (Windows and Unix)\n\n\
38
This compound pattern matches Windows- and Unix-style line delimiters, i.e.\n\
39
- Windows (\\r\\n)\n\
40
- Unix (\\n)\n\n\
41
Note that this pattern does not work properly inside [].
42
displayString_bs_rn= (\\r\\n?|\\n) - Line delimiter (platform independent)
43
additionalInfo_bs_rn= Line delimiter (platform independent)\n\n\
44
This compound pattern matches any form of line delimiters, i.e.\n\
45
- Windows (\\r\\n)\n\
46
- Unix (\\n)\n\
47
- Mac OS 9 (\\r)\n\n\
48
Note that this pattern does not work inside [], and\n\
49
that it introduces a capturing group.
28
displayString_bs_f= \\f - FF
50
displayString_bs_f= \\f - FF
29
additionalInfo_bs_f= Form Feed (\\x0C, decimal: 12)
51
additionalInfo_bs_f= Form Feed (\\x0C, decimal: 12)
30
displayString_bs_a= \\a - Beep
52
displayString_bs_a= \\a - Beep
31
additionalInfo_bs_a= Beep, Bell, Alert (\\x07, decimal: 7)
53
additionalInfo_bs_a= Beep, Bell, Alert (\\x07, decimal: 7)
32
displayString_bs_e= \\e - Esc
54
displayString_bs_e= \\e - Esc
33
additionalInfo_bs_e= Escape (\\x1B, decimal: 27)
55
additionalInfo_bs_e= Escape (\\x1B, decimal: 27)
34
displayString_bs_c= \\c - Control character
56
displayString_bs_c= \\cC - Control character
35
additionalInfo_bs_c= Control character\n\nExample:\n\\cC (Ctrl+C)
57
additionalInfo_bs_c= Control character for C\n\nExample:\n\\cC (Ctrl+C, \\x03, decimal: 3)
36
58
37
displayString_dot= . - Any character
59
displayString_dot= . - Any character
38
additionalInfo_dot= The dot matches any character except line terminators.\n\n\
60
additionalInfo_dot= The dot matches any character except line terminators.\n\n\
Lines 214-221 Link Here
214
Matches the preceding token if possible. Never backtracks,\n\
236
Matches the preceding token if possible. Never backtracks,\n\
215
even if this choice renders a full match impossible.\n\nExample:\n\
237
even if this choice renders a full match impossible.\n\nExample:\n\
216
The expression "fo?+o\\d" matches the first, but not the second line in text\n\
238
The expression "fo?+o\\d" matches the first, but not the second line in text\n\
217
"fo1\n\
239
"foo1\n\
218
foo1".
240
fo1".
219
displayString_starPoss= *+ Possessive match 0 or more times (no backtracking)
241
displayString_starPoss= *+ Possessive match 0 or more times (no backtracking)
220
additionalInfo_starPoss= Possessive match 0 or more times.\n\n\
242
additionalInfo_starPoss= Possessive match 0 or more times.\n\n\
221
Tries to match the preceding token as many times as possible. Never backtracks,\n\
243
Tries to match the preceding token as many times as possible. Never backtracks,\n\
Lines 483-496 Link Here
483
$0 is the subsequence matched by the entire expression.\n\
505
$0 is the subsequence matched by the entire expression.\n\
484
\n\
506
\n\
485
Note: in the find expression, \\i stands for the capturing group i. 
507
Note: in the find expression, \\i stands for the capturing group i. 
508
displayString_replace_cap= \\i - Match of the capturing group i
509
additionalInfo_replace_cap= Match of the capturing group i.\n\n\
510
\\i is the string that has been saved as capturing group i.\n\
511
\\0 is the subsequence matched by the entire expression.\n\
512
\n\
513
Note: \\i is equivalent to $i 
486
displayString_replace_bs= \\ - Quote next character
514
displayString_replace_bs= \\ - Quote next character
487
additionalInfo_replace_bs= Quote next character\n\nExamples:\n\
515
additionalInfo_replace_bs= Quote next character\n\nExamples:\n\
488
"\\$" will be replaced by "$".\n\
516
"\\$" will be replaced by "$".\n\
489
"\\a" will be replaced by "a".\n\
517
"\\q" will be replaced by "q".\n\
490
"\\\\" will be replaced by "\\".
518
"\\\\" will be replaced by "\\".
491
displayString_tab= Tab - The tabulator character
519
displayString_replace_bs_n= \\n - Newline
492
additionalInfo_tab= The tabulator character (\\t in the find expression).
520
additionalInfo_replace_bs_n= Newline (\\x0A, decimal: 10)\n\n\
493
displayString_cr= CR - The carriage return character
521
Note that \\n always inserts the newline character,\n\
494
additionalInfo_cr= The carriage return character (\\r or \\x0D in the find expression).
522
even if the document uses different line delimiters.\n\n\
495
displayString_nl= Newline - The newline character
523
To insert the document line delimiter, use \\R.
496
additionalInfo_nl= The newline character (\\n or \\x0A in the find expression).
524
displayString_replace_bs_r= \\r - CR
525
additionalInfo_replace_bs_r= Carriage Return (\\x0D, decimal: 13)\n\n\
526
Note that \\r always inserts the carriage return character,\n\
527
even if the document uses different line delimiters.\n\n\
528
To insert the document line delimiter, use \\R.
529
displayString_replace_bs_R= \\R - Line delimiter
530
additionalInfo_replace_bs_R= Line delimiter\n\n\
531
Inserts the default line delimiter of the document.
(-)src/org/eclipse/jface/text/FindReplaceDocumentAdapter.java (+215 lines)
Lines 175-180 Link Here
175
				Pattern pattern= fFindReplaceMatcher.pattern();
175
				Pattern pattern= fFindReplaceMatcher.pattern();
176
				Matcher replaceTextMatcher= pattern.matcher(fFindReplaceMatcher.group());
176
				Matcher replaceTextMatcher= pattern.matcher(fFindReplaceMatcher.group());
177
				try {
177
				try {
178
					replaceText= interpretCharacterEscapes(replaceText);
178
					replaceText= replaceTextMatcher.replaceFirst(replaceText);
179
					replaceText= replaceTextMatcher.replaceFirst(replaceText);
179
				} catch (IndexOutOfBoundsException ex) {
180
				} catch (IndexOutOfBoundsException ex) {
180
					throw new PatternSyntaxException(ex.getLocalizedMessage(), replaceText, -1);
181
					throw new PatternSyntaxException(ex.getLocalizedMessage(), replaceText, -1);
Lines 228-233 Link Here
228
	}
229
	}
229
230
230
	/**
231
	/**
232
	 * Interprets escaped characters in the given replace pattern.
233
	 * 
234
	 * @param replaceText the replace pattern
235
	 * @return a replace pattern with escaped characters substituted by the respective characters
236
	 */
237
	private String interpretCharacterEscapes(String replaceText) {
238
		int length= replaceText.length();
239
		boolean inEscape= false;
240
		StringBuffer buf= null;
241
		
242
		for (int i= 0; i < length; i++) {
243
			char ch= replaceText.charAt(i);
244
			if (inEscape) {
245
				switch (ch) {
246
					case 'r':
247
						buf= appendToBuffer('\r', buf, replaceText, i - 1);
248
						break;
249
					case 'n':
250
						buf= appendToBuffer('\n', buf, replaceText, i - 1);
251
						break;
252
					case 't':
253
						buf= appendToBuffer('\t', buf, replaceText, i - 1);
254
						break;
255
					case 'f':
256
						buf= appendToBuffer('\f', buf, replaceText, i - 1);
257
						break;
258
					case 'a':
259
						buf= appendToBuffer('\u0007', buf, replaceText, i - 1);
260
						break;
261
					case 'e':
262
						buf= appendToBuffer('\u001B', buf, replaceText, i - 1);
263
						break;
264
					case 'R': //see http://www.unicode.org/unicode/reports/tr18/#Line_Boundaries
265
						buf= appendToBuffer(TextUtilities.getDefaultLineDelimiter(fDocument), buf, replaceText, i - 1);
266
						break;
267
					/*
268
					 * \0 for octal is not supported in replace string, since it
269
					 * would conflict with capturing group \0, etc.
270
					 */
271
					case '0':
272
						buf= appendToBuffer('$', buf, replaceText, i - 1);
273
						buf.append(ch);
274
						/*
275
						 * Feature in java.util.regex.Matcher#replaceFirst(String):
276
						 * $00, $000, etc. are interpreted as $0 and
277
						 * $01, $001, etc. are interpreted as $1, etc. .
278
						 * If we support \0 as replacement pattern for capturing group 0,
279
						 * it would not be possible any more to write a replacement pattern
280
						 * that appends 0 to a capturing group (like $0\0).
281
						 * The fix is to consider \00 and $00 as $0\0, and
282
						 * \01 and $01 as $0\1, etc.
283
						 */
284
						if (i + 1 < length) {
285
							char nextCh= replaceText.charAt(i + 1);
286
							if ('0' <= nextCh && nextCh <= '9') {
287
								buf.append('\\');
288
								break;
289
							}
290
						}
291
						break;
292
						
293
					case '1':
294
					case '2':
295
					case '3':
296
					case '4':
297
					case '5':
298
					case '6':
299
					case '7':
300
					case '8':
301
					case '9':
302
						buf= appendToBuffer('$', buf, replaceText, i - 1);
303
						buf.append(ch);
304
						break;
305
306
					case 'c':
307
						if (i + 1 < length) {
308
							ch= replaceText.charAt(i + 1);
309
							buf= appendToBuffer((char) (ch ^ 64), buf, replaceText, i - 1);
310
							i++;
311
						} else {
312
							String msg= TextMessages.getFormattedString(
313
									"FindReplaceDocumentAdapter.illegalControlEscape", //$NON-NLS-1$
314
									"\\c"); //$NON-NLS-1$
315
							throw new PatternSyntaxException(msg, replaceText, i);
316
						}
317
						break;
318
						
319
					case 'x':
320
						if (i + 2 < length) {
321
							int parsedInt;
322
							try {
323
								parsedInt= Integer.parseInt(replaceText.substring(i + 1, i + 3), 16);
324
								if (parsedInt < 0)
325
									throw new NumberFormatException();
326
							} catch (NumberFormatException e) {
327
								String msg= TextMessages.getFormattedString(
328
										"FindReplaceDocumentAdapter.illegalHexEscape", //$NON-NLS-1$
329
										replaceText.substring(i - 1, i + 3));
330
								throw new PatternSyntaxException(msg, replaceText, i);
331
							}
332
							buf= appendToBuffer((char) parsedInt, buf, replaceText, i - 1);
333
							i+= 2;
334
						} else {
335
							String msg= TextMessages.getFormattedString(
336
									"FindReplaceDocumentAdapter.illegalHexEscape", //$NON-NLS-1$
337
									replaceText.substring(i - 1, length));
338
							throw new PatternSyntaxException(msg, replaceText, i);
339
						}
340
						break;
341
						
342
					case 'u':
343
						if (i + 4 < length) {
344
							int parsedInt;
345
							try {
346
								parsedInt= Integer.parseInt(replaceText.substring(i + 1, i + 5), 16);
347
								if (parsedInt < 0)
348
									throw new NumberFormatException();
349
							} catch (NumberFormatException e) {
350
								String msg= TextMessages.getFormattedString(
351
										"FindReplaceDocumentAdapter.illegalUnicodeEscape", //$NON-NLS-1$
352
										replaceText.substring(i - 1, i + 5));
353
								throw new PatternSyntaxException(msg, replaceText, i);
354
							}
355
							buf= appendToBuffer((char) parsedInt, buf, replaceText, i - 1);
356
							i+= 4;
357
						} else {
358
							String msg= TextMessages.getFormattedString(
359
									"FindReplaceDocumentAdapter.illegalUnicodeEscape", //$NON-NLS-1$
360
									replaceText.substring(i - 1, length));
361
							throw new PatternSyntaxException(msg, replaceText, i);
362
						}
363
						break;
364
						
365
					default:
366
						if (buf != null)
367
							buf.append('\\').append(ch);
368
						break;
369
				}
370
				inEscape= false;
371
				
372
			} else if (ch == '\\') {
373
				inEscape= true;
374
				
375
			} else if (ch == '$') {
376
				if (buf != null) {
377
					buf.append(ch);
378
				}
379
				// see explanation above in "Feature in java.util.regex.Matcher#replaceFirst(String)"
380
				if (i + 2 < length) {
381
					char ch1= replaceText.charAt(i + 1);
382
					char ch2= replaceText.charAt(i + 2);
383
					if (ch1 == '0' && '0' <= ch2 && ch2 <= '9') {
384
						i++; // consume the 0
385
						buf= appendToBuffer("0\\", buf, replaceText, i); //$NON-NLS-1$
386
					}
387
				} else
388
				break;
389
				
390
			} else if (buf != null) {
391
				buf.append(ch);
392
			}
393
		}
394
		
395
		if (buf != null) {
396
			if (inEscape) {
397
				// '\' as last character is invalid, but we still add it to get an error message
398
				buf.append('\\');
399
			}
400
			return buf.toString();
401
		}
402
		return replaceText;
403
	}
404
405
	/**
406
	 * Creates or reuses a string buffer and appends a string to the buffer.
407
	 * If <code>buf</code> is <code>null</code>, a new buffer is created
408
	 * from <code>completeText.substring(0, i)</code>.
409
	 * Callers should use the result as new buffer.
410
	 * 
411
	 * @param str string to append
412
	 * @param buf the existing buffer, or <code>null</code>
413
	 * @param completeText the complete text
414
	 * @param i the index into <code>completeText</code>
415
	 * 
416
	 * @return the buffer
417
	 */
418
	private StringBuffer appendToBuffer(String str, StringBuffer buf, String completeText, int i) {
419
		if (buf == null)
420
			buf= new StringBuffer(completeText.substring(0, i));
421
		buf.append(str);
422
		return buf;
423
	}
424
425
	/**
426
	 * Creates or reuses a string buffer and appends a character to the buffer.
427
	 * If <code>buf</code> is <code>null</code>, a new buffer is created
428
	 * from <code>completeText.substring(0, i)</code>.
429
	 * Callers should use the result as new buffer.
430
	 * 
431
	 * @param ch string to append
432
	 * @param buf the existing buffer, or <code>null</code>
433
	 * @param completeText the complete text
434
	 * @param i the index into <code>completeText</code>
435
	 * 
436
	 * @return the buffer
437
	 */
438
	private static StringBuffer appendToBuffer(char ch, StringBuffer buf, String completeText, int i) {
439
		if (buf == null)
440
			buf= new StringBuffer(completeText.substring(0, i));
441
		buf.append(ch);
442
		return buf;
443
	}
444
445
	/**
231
	 * Converts a non-regex string to a pattern
446
	 * Converts a non-regex string to a pattern
232
	 * that can be used with the regex search engine.
447
	 * that can be used with the regex search engine.
233
	 *
448
	 *
(-)src/org/eclipse/jface/text/TextMessages.properties (+14 lines)
Added Link Here
1
###############################################################################
2
# Copyright (c) 2007 IBM Corporation and others.
3
# All rights reserved. This program and the accompanying materials
4
# are made available under the terms of the Eclipse Public License v1.0
5
# which accompanies this distribution, and is available at
6
# http://www.eclipse.org/legal/epl-v10.html
7
#
8
# Contributors:
9
#     IBM Corporation - initial API and implementation
10
###############################################################################
11
12
FindReplaceDocumentAdapter.illegalControlEscape=Illegal control escape sequence {0}
13
FindReplaceDocumentAdapter.illegalHexEscape=Illegal hexadecimal escape sequence {0}
14
FindReplaceDocumentAdapter.illegalUnicodeEscape=Illegal Unicode escape sequence {0}
(-)src/org/eclipse/jface/text/TextMessages.java (+42 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2007 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.jface.text;
12
13
import java.util.MissingResourceException;
14
import java.util.ResourceBundle;
15
16
import com.ibm.icu.text.MessageFormat;
17
18
public class TextMessages {
19
	private static final String BUNDLE_NAME= "org.eclipse.jface.text.TextMessages"; //$NON-NLS-1$
20
21
	private static final ResourceBundle RESOURCE_BUNDLE= ResourceBundle.getBundle(BUNDLE_NAME);
22
23
	private TextMessages() {
24
	}
25
26
	public static String getString(String key) {
27
		try {
28
			return RESOURCE_BUNDLE.getString(key);
29
		} catch (MissingResourceException e) {
30
			return '!' + key + '!';
31
		}
32
	}
33
	
34
	public static String getFormattedString(String key, Object arg) {
35
		return getFormattedString(key, new Object[] { arg });
36
	}
37
38
	public static String getFormattedString(String key, Object[] args) {
39
		return MessageFormat.format(getString(key), args);
40
	}
41
42
}
(-)src/org/eclipse/text/tests/FindReplaceDocumentAdapterTest.java (+55 lines)
Lines 211-216 Link Here
211
		}
211
		}
212
	}
212
	}
213
	
213
	
214
	public void testRegexReplace() throws Exception {
215
		fDocument.set(
216
				"UnixWindowsMacInferred\n" +
217
				"Chars"
218
		);
219
		FindReplaceDocumentAdapter findReplaceDocumentAdapter= new FindReplaceDocumentAdapter(fDocument);
220
		regexReplace("Unix", "$0\\n", findReplaceDocumentAdapter);
221
		regexReplace("(Windows)", "$1\\r\\n", findReplaceDocumentAdapter);
222
		regexReplace("(M)ac", "\\0\\r", findReplaceDocumentAdapter);
223
		regexReplace("(Inferred)", "\\1\\R", findReplaceDocumentAdapter);
224
		regexReplace("Chars", "\\\\, \\xF6, \\u00F6, \\t, \\n, \\r, \\f, \\a, \\e, \\cF", findReplaceDocumentAdapter);
225
			
226
		String text= "Unix\nWindows\r\nMac\rInferred\n\n" +
227
			"\\, \u00F6, \u00F6, \t, \n, \r, \f, \u0007, \u001B, \u0006";
228
		assertEquals(text, fDocument.get());
229
	}
230
	
231
	public void testRegexReplace2() throws Exception {
232
		FindReplaceDocumentAdapter findReplaceDocumentAdapter= new FindReplaceDocumentAdapter(fDocument);
233
		
234
		fDocument.set("foo");
235
		regexReplace("foo", "\\00", findReplaceDocumentAdapter);
236
		assertEquals("foo0", fDocument.get());
237
		
238
		fDocument.set("foo");
239
		regexReplace("foo", "\\010", findReplaceDocumentAdapter);
240
		assertEquals("foo10", fDocument.get());
241
		
242
		fDocument.set("foo");
243
		regexReplace("foo", "$00", findReplaceDocumentAdapter);
244
		assertEquals("foo0", fDocument.get());
245
		
246
		fDocument.set("foo");
247
		regexReplace("foo", "$010", findReplaceDocumentAdapter);
248
		assertEquals("foo10", fDocument.get());
249
	}
250
	
251
	public void testRegexReplace3() throws Exception {
252
		FindReplaceDocumentAdapter findReplaceDocumentAdapter= new FindReplaceDocumentAdapter(fDocument);
253
		
254
		fDocument.set("foo");
255
		regexReplace("(f)oo", "\\10", findReplaceDocumentAdapter);
256
		assertEquals("f0", fDocument.get());
257
		
258
		fDocument.set("foo");
259
		regexReplace("(f)oo", "$10", findReplaceDocumentAdapter);
260
		assertEquals("f0", fDocument.get());
261
	}
262
	
263
	private void regexReplace(String find, String replace, FindReplaceDocumentAdapter findReplaceDocumentAdapter) throws BadLocationException {
264
		findReplaceDocumentAdapter.find(0, find, true, true, false, true); //$NON-NLS-1$
265
		IRegion r= findReplaceDocumentAdapter.replace(replace, true); //$NON-NLS-1$
266
		assertNotNull(r);
267
	}
268
	
214
	public void testIllegalState() {
269
	public void testIllegalState() {
215
		FindReplaceDocumentAdapter findReplaceDocumentAdapter= new FindReplaceDocumentAdapter(fDocument);
270
		FindReplaceDocumentAdapter findReplaceDocumentAdapter= new FindReplaceDocumentAdapter(fDocument);
216
		try {
271
		try {

Return to bug 80667