|
12. Text Conversion Rules
Find And Replace is the canonical form of conversion
that we use in various text editors and integrated development environments.
In TextMaestro, it attains a new level and thus incurs a small learning
curve. It is so due to the power of wild-card and type-card usage. User
defines a macro that consists of two parts - Find
and Replace. The
macro has certain attributes. This macro governs the conversion.
Here we discuss the following:
Usage
(1) Basic find-and-replace
(2) Use of wild-card
(2.1) Generic
wild-card
(2.2) Special
characteristics of wild-card
(2.2.1)
Wild-card by itself
(2.2.2)
Wild-card and line-break
(3) Use of
type-card
Knobs
(1) Per-line
search
(2) Compact
construct
(3) Filter
processed text
(4) Delimiter
parse
Qualifiers
(a) Trim
Argument
(b) Case
Argument
(c) Clean
Argument
(d) Align
Argument
(e) Increment
Argument
Comments
Usage Top
(1)
Basic find-and-replace: Top
Consider the following input text:
|
Input |
|
//---------------------------------------------------------
// Session info
//---------------------------------------------------------
CSession::CSession()
{
m_CreateDir
= "Yes";
m_IsLoaded
= "No";
} |
Consider this macro:
|
Find: |
|
//---------------------------------------------------------
// Session info
//--------------------------------------------------------- |
|
Replace: |
|
/*
* TextMaestro
Technologies
* Base
constructor initialization of CSession
*/ |
With these definitions, we get the following output
text:
|
Output |
|
/*
* TextMaestro
Technologies
* Base
constructor initialization of CSession
*/
CSession::CSession()
{
m_CreateDir
= "Yes";
m_IsLoaded
= "No";
} |
Definitions of Find
and Replace may
contain line breaks. Find
can be case-insensitive.
(2)
Use of wild-card: Top
When
you define a macro, either in Work Pad
or Find-And-Replace
Library, you may choose to check Use wild-card.
If you do so, the scheme enters in a mode where wild-card and type-card
dictate a 'grammar' based conversion.
(2.1)
Generic wild-card: Top
Concept of wild-card can be viewed as pattern-matching.
Wild-card is a place holder for arbitrary text on the path of parsing.
If the non-wild-card text combined with wild-card text is found in the
input text, then the conversion recognizes it as a match. Consider the
following input:
|
Input |
|
void CSession::WriteSessionHeaderInfo(ofstream& temp_out,
int s_ind)
{
CString
_t;
temp_out
<< "SessionName=" <<
LPCTSTR(m_SessionName)<<
", ";
temp_out
<< "Host=" <<
LPCTSTR(m_Host)
<<
", ";
temp_out
<< "HostType=" <<
LPCTSTR(m_HostType)
<<
", ";
temp_out
<< "User=" <<
LPCTSTR(m_User)
<<
", ";
temp_out
<< "RemoteDir=" <<
LPCTSTR(m_RemoteDir)
<<
", ";
temp_out
<< "LocalDir=" <<
LPCTSTR(m_LocalDir)
<<
", ";
temp_out
<< "SessionBox=" <<
LPCTSTR(m_SessionBox)
<< ", ";
temp_out
<< "CreateDir=" <<
LPCTSTR(m_CreateDir)
<<
", ";
} |
Consider this macro:
|
Find: |
"*=" |
|
Replace: |
"*: " |
With these definitions, we get the following output:
|
Output |
|
void CSession::WriteSessionHeaderInfo(ofstream& temp_out,
int s_ind)
{
CString
_t;
temp_out
<< "SessionName: " <<
LPCTSTR(m_SessionName)<<
", ";
temp_out
<< "Host: " <<
LPCTSTR(m_Host)
<<
", ";
temp_out
<< "HostType: " <<
LPCTSTR(m_HostType)
<<
", ";
temp_out
<< "User: " <<
LPCTSTR(m_User)
<<
", ";
temp_out
<< "RemoteDir: " <<
LPCTSTR(m_RemoteDir)
<<
", ";
temp_out
<< "LocalDir: " <<
LPCTSTR(m_LocalDir)
<<
", ";
temp_out
<< "SessionBox: " <<
LPCTSTR(m_SessionBox)
<< ", ";
temp_out
<< "CreateDir: " <<
LPCTSTR(m_CreateDir)
<<
", ";
} |
After a "
is found, the search keeps assimilating characters until it finds =. What it finds on
the way, becomes argument denoted by *
in Replace. That
is to say, you can use wild-card in Replace
as a place-holder of the argument constructed during parsing.
Consider the following macro:
|
Find: |
"*"*<<*LPCTSTR(*)*<<* |
|
Replace: |
"<*1>"
+ <*4> + <*6> |
If you match the wild-cards in Find for a certain
line, you will notice that first, fourth and sixth wild-card denote some
tokens of interest. So we use those wild-cards in Replace in the form
of <*n>.
Thus, we get this output:
|
Output |
|
void CSession::WriteSessionHeaderInfo(ofstream& temp_out,
int s_ind)
{
CString
_t;
temp_out
<< "SessionName="
+ m_SessionName + ", ";
temp_out
<< "Host=" + m_Host + ",
";
temp_out
<< "HostType=" +
m_HostType + ", ";
temp_out
<< "User=" + m_User + ", ";
temp_out
<< "RemoteDir=" +
m_RemoteDir + ", ";
temp_out
<< "LocalDir=" +
m_LocalDir + ", ";
temp_out
<< "SessionBox="
+ m_SessionBox + ",
";
temp_out
<< "CreateDir=" +
m_CreateDir + ", ";
} |
Sometimes user might need to use "*" in
Find and/or Replace as non-wild-card
in a wild-card mode search. In that case, some other character, for example
"@", "~", "#", etc. can be used to denote
wild-card. When you define a find-and-replace macro from Work
Pad or Find And
Replace Library you have the option to specify the wild-card character.
For above example, if you had specified wild-card flag as "@",
the macro would look like this:
|
Find: |
"@"@<<@LPCTSTR(@)@<<@ |
|
Replace: |
"<@1>"
+ <@4> + <@6> |
Consider the following input:
|
Input |
|
InfoTech_01_Program.htm im_tech_sess_man01.gif
InfoTech_02_ToolbarMain.htm im_tech_sess_man02.gif
InfoTech_03_TBSession.htm im_tech_sess_man03.gif
InfoTech_04_TBFtp.htm im_tech_sess_man04.gif
|
Now consider the following macro:
|
Find: |
* * |
|
Replace: |
* contains * |
Here is the output:
|
Output |
|
InfoTech_01_Program.htm contains im_tech_sess_man01.gif
InfoTech_02_ToolbarMain.htm contains im_tech_sess_man02.gif
InfoTech_03_TBSession.htm contains im_tech_sess_man03.gif
InfoTech_04_TBFtp.htm contains im_tech_sess_man04.gif
|
Note that in Replace
you can have wild-card in non-ordinal form. In that case wild-cards in
Replace are resolved
in the order they are found. I.e., the first wild-card stands for the
first argument, and the second wild-card, for the second argument, and
so on. It is recommended that you specify wild-cards in Replace
in ordinal format (<*n>)
for clarity.
(2.2)
Special characteristics of wild-card:
Top
There are a few special characteristics of wild-card
usage. If you are not familiar with them, you might find some of the wild-card
effects unexpected. Once familiar, those special characteristics rather
become handy.
(2.2.1)
Wild-card by itself: Top
Find
consisting of single wild-card denotes the whole line. Consider
the following input:
|
Input |
|
void CTextCvt::SetCurrentIndex()
{
m_dnLibInd_TP
= CStaticLibraryDlg::m_nLibInd_TP;
m_dnLibInd_FR
= CStaticLibraryDlg::m_nLibInd_FR;
m_dnLibInd_KL
= CStaticLibraryDlg::m_nLibInd_KL;
} |
Consider the following macro:
Here is the output:
|
Output |
|
// void CTextCvt::SetCurrentIndex()
// {
// m_dnLibInd_TP
= CStaticLibraryDlg::m_nLibInd_TP;
// m_dnLibInd_FR
= CStaticLibraryDlg::m_nLibInd_FR;
// m_dnLibInd_KL
= CStaticLibraryDlg::m_nLibInd_KL;
// } |
On the other hand, Find
consisting of double wild-cards denotes the whole input. With the following
macro:
|
Find: |
@@ |
|
Replace: |
/*
-------------------------------------------------------
@@
-------------------------------------------------------
*/ |
we get the following output from the above input:
|
Output |
|
/*
-------------------------------------------------------
void CTextCvt::SetCurrentIndex()
{
m_dnLibInd_TP
= CStaticLibraryDlg::m_nLibInd_TP;
m_dnLibInd_FR
= CStaticLibraryDlg::m_nLibInd_FR;
m_dnLibInd_KL
= CStaticLibraryDlg::m_nLibInd_KL;
}
-------------------------------------------------------
*/ |
Note that we had to switch to "@" for wild-card,
since we used "*" as non-wild-card in Replace.
(2.2.2)
Wild-card and line-break: Top
Wild-card at the beginning of Find
denotes text from the previous line-break. Consider the following macro.
From the same input above we get the following output:
|
Output |
|
void CTextCvt::SetCurrentIndex()
{
// m_dnLibInd_TP
= CStaticLibraryDlg::m_nLibInd_TP;
// m_dnLibInd_FR
= CStaticLibraryDlg::m_nLibInd_FR;
// m_dnLibInd_KL
= CStaticLibraryDlg::m_nLibInd_KL;
} |
In similar fashion, wild-card at the end of Find denotes text to
the next line-break. Consider the following macro:
|
Find: |
=* |
|
Replace: |
= 0; // * |
which creates this output:
|
Output |
|
void CTextCvt::SetCurrentIndex()
{
m_dnLibInd_TP
= 0; // CStaticLibraryDlg::m_nLibInd_TP;
m_dnLibInd_FR
= 0; // CStaticLibraryDlg::m_nLibInd_FR;
m_dnLibInd_KL
= 0; // CStaticLibraryDlg::m_nLibInd_KL;
} |
(3)
Use of type-card: Top
Similar to wild-card, there is a parallel concept
of type-card. Type-card can be used only when Use
wild-card is checked. Let us begin with an example. Consider the
following input:
|
Input |
|
Each macro
you
define
can be
stored
in a
library.
When you
click
on the
convert button
from the
library
panel, you
basically
execute
the
active
macros
of
the
library sequentially.
Using
a
library of
macros on
an
input is
a
whole
new
level
of
muscle
to flex. |
Note the occurrences of multiple blanks, which ideally
should be just one blank. One or many consecutive blanks are denoted by
^b type-card.
Consider the following macro:
|
Find: |
^b |
|
Replace: |
(blank) |
which gives the following output:
|
Output |
|
Each macro you define can be stored in a library.
When you click on the convert button from the library
panel, you basically execute the active macros of the
library sequentially. Using a library of macros on an
input is a whole new level of muscle to flex. |
By default, there are six kinds of type-cards per
library:
|
|
When used in wild-card mode denotes: |
|
|
^b |
one or many consecutive blank spaces (' '
and/or tabs). |
(Blank) |
|
^n |
one or many consecutive line-breaks (accepting
blanks on the way). |
(\n) |
|
^a |
one or many consecutive characters from a-z
and A-Z sets. |
(Alpha) |
|
^d |
one or many consecutive characters from 0-9
sets. |
(Digit) |
|
^m |
one or many consecutive math operators: +
- * / < > { } [ ] ( ) = |
(math) |
|
^p |
one or more consecutive punctuation operators:
, . : ; " ' |
(punctuation) |
User can define his own set of type-cards using Wild-card Manager. See
more.
Here are some examples. Consider the following input:
|
Input |
|
Box05-Ses25-Get-Bld-92903.txt 10
Box05-Ses26-Importedtest.jpg 10
Box05-Ses27-Hypnos.gif 10
Box05-Ses28-Hypnos-Part.txt 11
Box05-Ses29-Hypnos-Linux-Build.txt 11
Box06-Ses30-Text-Pos.txt 12
Box07-Ses31-Inter-Dev.com 12
Box07-Ses32-Inter-Port.txt 12
Box07-Ses33-Test-Suit.txt 13
Box07-Ses34-Test-Match.bmp 14
Box07-Ses35-Test-New.txt 15 |
Consider this macro:
|
Find: |
^a^d^m^a^d^m*.^a*^d |
|
Replace: |
*.<^a3><a=30><^d3> |
which gives the following output:
|
Output |
|
Get-Bld-92903.txt
10
Importedtest.jpg
10
Hypnos.gif
10
Hypnos-Part.txt
11
Hypnos-Linux-Build.txt
11
Text-Pos.txt
12
Inter-Dev.com
12
Inter-Port.txt
12
Test-Suit.txt
13
Test-Match.bmp
14
Test-New.txt
15 |
Compare the color high-lighting of the first line
of Input with
that of Find.
|
Find: |
^a^d^m^a^d^m*.^a^b^d |
|
First line: |
Box05-Ses25-Get-Bld-92903.txt
10
+-----------+
* |
Notice how * stands for Get-Bld-92903,
3rd <^a>
for txt
and 3rd <^d>
for 10. In Replace
we accessed 3rd <^a>
by <^a3>,
and 3rd <^d>
by <^d3>.
That is to say, type-cards can be accessed by their ordinals, just like
the wild-cards.
As an exercise, now consider the following macro:
|
Find: |
^a^d^m^a^d^m*.^a*^d |
|
Replace: |
*.<^a3><a=30?.><^a1>
<^d1><a=45?.><^a2>
<^d2><a=60?.><^d3> |
which gives the following output:
|
Output |
|
Get-Bld-92903.txt............Box 05.........Ses 25.........10
Importedtest.jpg.............Box 05.........Ses 26.........10
Hypnos.gif...................Box 05.........Ses 27.........10
Hypnos-Part.txt..............Box 05.........Ses 28.........11
Hypnos-Linux-Build.txt.......Box 05.........Ses 29.........11
Text-Pos.txt.................Box 06.........Ses 30.........12
Inter-Dev.com................Box 07.........Ses 31.........12
Inter-Port.txt...............Box 07.........Ses 32.........12
Test-Suit.txt................Box 07.........Ses 33.........13
Test-Match.bmp...............Box 07.........Ses 34.........14
Test-New.txt.................Box 07.........Ses 35.........15 |
It is apparent that various type-cards are used in
Replace to generate
various columns above. What might not be so obvious is the use of qualifier
<a=m>.
There are four types of qualifiers. We will discuss them here.
Comments:
(a) User can configure (define) his own set of type-cards by using Wild-Card Manager which
is found under Work-Pad
and Find-Replace
library.
(b) Unlike wild-card, rules behind type-cards are
simple. However, there is one note-worthy similarity -- the concept of
arguments to re-arrange wild-cards holds for type-cards.
(c) Type-cards are available only in Find-and-replace
scheme.
Knobs Top
(1)
Per-line search: Top
Recall, wild-card search continues parsing arbitrary
text until it matches non-wild text. This search continues even if a line-break
is encountered on the way. There comes time when a wild-card search spilling
over a line-break becomes undesirable. Consider the following input:
|
Input |
|
1.
m_tech_cvt_batch_01.gif
2.
m_tech_sch_batch_01.gif
3.
m_tech_cvt_batch_02.htm
4.
m_tech_sch_batch_02.gif
5.
m_tech_cvt_qhelp_01.gif
6.
m_tech_sch_qhelp_01.gif
7.
m_tech_cvt_qhelp_03.htm
8.
m_tech_sch_qhelp_04.gif
9.
m_tech_cvt_scheme_01.htm
10.
m_tech_sch_scheme_01.htm |
Suppose we want to get handle of the files that have
cvt and htm. One might think cvt*htm would do the job. Not quite. The parsing
finds cvt in line 1, then it keeps
marching until it finds htm, which happens in line 3. Thereby, all the
text from cvt to htm spanning over line 1, 2 and 3 becomes the
found text. Note the color code in input shown below:
|
Color high-light of input |
|
1.
m_tech_cvt_batch_01.gif
2.
m_tech_sch_batch_01.gif
3.
m_tech_cvt_batch_02.htm
4.
m_tech_sch_batch_02.gif
5.
m_tech_cvt_qhelp_01.gif
6.
m_tech_sch_qhelp_01.gif
7.
m_tech_cvt_qhelp_03.htm
8.
m_tech_sch_qhelp_04.gif
9.
m_tech_cvt_scheme_01.htm
10.
m_tech_sch_scheme_01.htm |
Certainly, using cvt*htm will not give you the
desired result. Although sometimes it is feasible to define Find
so that the parsing remains within a line, bear in mind that it will become
unnecessarily complicated, when you have a choice of forcing the wild-card
search to become per-line search. When you define a macro in Work
Pad or Find And
Replace Library, check on Per-line
search. In that mode, parsing that is about to spill to the next
line is discontinued and a new search begins from the next line. In other
words, when cvt*htm is not found
in line 1, the current search will be discontinued, and it will resume
from line 2. In line 2, cvt*htm
is an immediate miss. So it will discontinue this search as well and begin
another from line 3. And there it will be a hit.
In summary, use Per-line
search as appropriate and
it will keep you out of messy run-through
problem.
Consider this macro:
|
Find: |
*cvt*htm |
|
Replace: |
Found file is: *cvt*htm |
|
Per-line search
- not
checked |
The output, albeit undesirable is this:
|
Output |
|
Found file is: 1.
m_tech_cvt_batch_01.gif
2.
m_tech_sch_batch_01.gif
3.
m_tech_cvt_batch_02.htm
4.
m_tech_sch_batch_02.gif
Found file is: 5.
m_tech_cvt_qhelp_01.gif
6.
m_tech_sch_qhelp_01.gif
7.
m_tech_cvt_qhelp_03.htm
8.
m_tech_sch_qhelp_04.gif
Found file is: 9.
m_tech_cvt_scheme_01.htm
10.
m_tech_sch_scheme_01.htm |
Consider this macro:
|
Find: |
*cvt*htm |
|
Replace: |
Found file is: *cvt*htm |
|
Per-line search
- checked |
The output is:
|
Output |
|
1.
m_tech_cvt_batch_01.gif
2.
m_tech_sch_batch_01.gif
Found file is: 3.
m_tech_cvt_batch_02.htm
4.
m_tech_sch_batch_02.gif
5.
m_tech_cvt_qhelp_01.gif
6.
m_tech_sch_qhelp_01.gif
Found file is: 7.
m_tech_cvt_qhelp_03.htm
8.
m_tech_sch_qhelp_04.gif
Found file is: 9.
m_tech_cvt_scheme_01.htm
10.
m_tech_sch_scheme_01.htm |
(2)
Compact construct: Top
Use of Compact
construct is somewhat similar to Per-line
search where you over-ride the blind
pattern matching. The difference between Per-line
search and Compact
construct is: while effect of the former reflects on line by line,
that of the latter is on block by block. Consider the following input:
|
Input |
|
Begin
line
1
line
2
End
Begin
line
1
999
line
2
End |
Suppose we want to get handle of the second block
using the text 999. One might
think Begin*999*End
would do the job. Not really. The parsing finds Begin in line 1, then it keeps marching until
it finds 999, and then it goes on
to look for the following End. Thus
parsing returns both block one and block two for Begin*999*End. That is the case when you do not check
on Compact construct.
However, with Compact
construct checked, parsing will return the second block only. In
that case, search handle is advanced to determine if a match can be obtained
within the current match. If so, parsing returns the match of shorter
span. Otherwise, the original match remains effective. In other words,
Compact construct
advances search handle to make Find
of minimal span.
|
This is the color-highlighting of parsing for Begin*999*End when Compact
construct is not checked.
|
Colored input |
|
Begin
line
1
line
2
End
Begin
line
1
999
line
2
End |
|
This is the color-highlighting of parsing for Begin*999*End when Compact
construct is checked.
|
Colored input |
|
Begin
line
1
line
2
End
Begin
line
1
999
line
2
End |
|
Comments:
There are subtleties between Per-line
search and Compact
construct. There are cases where both will render exactly the same
effect. For example, if you use Compact
construct instead of Per-line
search (or both) on the input text in (4)
above, you will get the same results. It is so, because the work of Compact construct there
contains within each line. Whenever definition of Find
encompasses line-breaks, you should use Compact
construct, not Per-line
search. For the converse, you should prefer Per-line
search, although both are equivalent.
(3)
Filter processed text: Top
When you define a macro in Work
Pad or Find And
Replace Library, you can check on this option in order to extract
text of interest. If checked, the conversion process will keep only the
found-and-replaced text and discard the rest of input. This option is
also referred to as filtering text. It is useful when you want to excerpt
text of interest from a large amount of text. For example, consider the
following macro:
|
Find: |
*cvt*htm |
|
Replace: |
Found file is: *cvt*htm |
|
Per-line search
- checked |
|
Keep found-and-replaced text Only- checked |
Here is the output:
|
Output |
|
Found file is: 3.
m_tech_cvt_batch_02.htm
Found file is: 7.
m_tech_cvt_qhelp_03.htm
Found file is: 9.
m_tech_cvt_scheme_01.htm |
(4)
Delimiter parse: Top
When you define a macro in Work
Pad or Find And
Replace Library, you can check on this option in order to force
the parsing to grab a block of text delimited by a pair delimiters. Here
is how it works:
Typically
you enter pair delimiters such as {},
(), [],
Begin End or what
ever you choose in Delimiter
List. No single delimiter is allowed for this option, neither it
makes sense. You can access Delimiter
List only if you check Use
Wild card option under Find.
Then
the scheme uses the delimiters in the order they are listed and construct
all blocks.
Next
it checks which of the blocks contain Find,
which can be defined by wild-cards, type-cards, and explicit string.
The blocks
that contain such Find
are replaced by the Replace
string, which can be constructed by wild-card, type-card and explicit
string.
Keep in mind that the whole block of text identified
by the pair of delimiters is replaced by Replace
string, no matter what it is.
Consider the following input and Find
and Replace:
|
Input |
|
Begin
line
1
line
2
Begin
line
3
line
4
load "C:\temp\foo.txt"
End
line
5
line
6
End
Begin
line
1
line
2
End |
|
|
Find: |
load "*" |
|
Replace: |
// File: * |
|
Delimiter parse -
checked |
|
Delimiter list contains - Begin
End |
|
For having Delimiter
parse checked and a pair delimiter Begin
End in the Delimiter
List, the red colored block above will be marked as a matched block,
since it contains load. Furthermore,
* will be composed as "C:\temp\foo.txt".
On the other hand, the second block of text does not have any load,
and thus it is not a hit. Therefore, we obtain the following output:
|
Input |
|
// File: C:\temp\foo.txt
Begin
line
1
line
2
End |
Comments:
It is interesting to note what happens if we do not have Delimiter
parse checked.
|
Input |
|
Begin
line
1
line
2
Begin
line
3
line
4
// File: C:\temp\foo.txt
End
line
5
line
6
End
Begin
line
1
line
2
End |
|
|
Find: |
load "*" |
|
Replace: |
// File: * |
|
Delimiter parse -
not checked |
In this case only Find
is replaced by Replace
string. Again, for Delimiter
parse case the whole text block (if it is a hit) is replaced by
the Replace string. |
Qualifiers Top
Like other conversion schemes, Find And Replace has
the following qualifiers.
(a)
Trim Argument Top
Using qualifier of the form <*n:s>,
where n is the argument number, you can keep at most left s characters
of the n-th argument. Similarly the qualifier <*n:-s> allows you to keep at most right s
characters of the n-th argument. For example, consider the following input:
|
Input |
|
IM_TECH_CVT_SCH_01.GIF
IM_TECH_CVT_SCH_02.GIF
IM_TECH_CVT_SCH_03.GIF
IM_TECH_CVT_SCH_04.GIF
IM_TECH_CVT_SCH_05.GIF |
With the following macro definition
|
Find: |
* |
|
Replace: |
<*1:2>__<*1:-6> |
we obtain the following output, where the arguments
are trimmed based on the specifications:
|
Output |
|
IM__01.GIF
IM__02.GIF
IM__03.GIF
IM__04.GIF
IM__05.GIF |
(b)
Case Argument Top
Using qualifier such as <*nl>, <*nu> and <*np>, where n is argument number, you can change the case of the arguments
to lower, upper and proper case, respectively. Consider this input:
|
Input |
|
IM_TECH_CVT_SCH_01.GIF
IM_TECH_CVT_SCH_02.GIF
IM_TECH_CVT_SCH_03.GIF
IM_TECH_CVT_SCH_04.GIF
IM_TECH_CVT_SCH_05.GIF |
With the following macro:
|
Find: |
*_*_*_*.* |
|
Replace: |
mv *_*_*_*.* <*1p>-<*2l>-<*3p>-<*4u>.<*5l> |
we obtain the following output, where the arguments
are changed to lower and proper case:
|
Output |
|
mv IM_TECH_CVT_sch_01.GIF Im-tech-Cvt-SCH_01.gif
mv IM_TECH_CVT_sch_02.GIF Im-tech-Cvt-SCH_02.gif
mv IM_TECH_CVT_sch_03.GIF Im-tech-Cvt-SCH_03.gif
mv IM_TECH_CVT_sch_04.GIF Im-tech-Cvt-SCH_04.gif
mv IM_TECH_CVT_sch_05.GIF Im-tech-Cvt-SCH_05.gif |
(c) Clean Argument Top
Using qualifier of the form <*n?find=rep>
you can perform inline find-and-replace to clean an argument. Consider
this input:
|
Input |
|
IM_TECH_CVT_SCH_01.GIF
IM_TECH_CVT_SCH_02.GIF
IM_TECH_CVT_SCH_03.GIF
IM_TECH_CVT_SCH_04.GIF
IM_TECH_CVT_SCH_05.GIF |
With the following macro:
|
Find: |
* |
|
Replace: |
mv <*1> <*1l?IM_TECH=__i?CVT_?sch=ScHeMe> |
we obtain the following output:
|
Output |
|
mv IM_TECH_CVT_SCH_01.GIF __i_scheme_01.gif
mv IM_TECH_CVT_SCH_02.GIF __i_scheme_02.gif
mv IM_TECH_CVT_SCH_03.GIF __i_scheme_03.gif
mv IM_TECH_CVT_SCH_04.GIF __i_scheme_04.gif
mv IM_TECH_CVT_SCH_05.GIF __i_scheme_05.gif |
Note the elaborate argument cleansing qualifier here.
The interpretation of this definition is as follows:
From the first argument (denoted by <$1l...>)
Find IM_TECH
and replace it by __i.
Find CVT_
and simply drop it off, since no =rep
is present.
Find sch and replace it by ScHeMe, since Match
case is ignored.
Finally due to case changing flag "l" in
<$1l...>,
set this argument-output in lowercase.
This inline find-and-replace in argument cleansing
is case-sensitive, and takes place in the order of listing.
This qualifier is indeed very powerful.
It is so because you can use wild-card and type-card features within the
arguments as next round of find-and-replace for the arguments. That goes
on to say, if needed one can have nested find-and-replace scheme, which
can also relate to the equivalence of using multiple macros from a library.
One of the classical examples in this regard is converting
C-style comments to C++ style. Consider the following input:
|
Input |
|
/*
=====================================================================
TextMaestro Technologies TM
All rights reserved.
=====================================================================
*/
/*
* This module determines the insert location of text
* for right-append feature.
*
*/
int CTextCvt::M_GetInsertLoc(CString
&temp)
{
int
len = temp.GetLength();
int
n=0;
n
= temp.ReverseFind(' '); /*
"23423423423234234" case, no blank */
if
(n<0) return 0;
if
(n==len-1){ /*
"123213 23423
"
case, trailing blanks */
while(1){
if
(temp.GetAt(n)==' ') n--; /*
clip tail blanks */
else
break;
}
temp
= temp.Mid(0, n);
}
n
= temp.ReverseFind(' '); /*
"231234 23234"
case, get pre blank. */
if
(n<0) n = 0; /*
needed for "12312312 "
case. */
return
n;
} |
Consider the following macro:
|
Find: |
/*@*/ |
|
Replace: |
<@1?@=//@> |
Here is the output: (Yes, you can align the in-line
C++-style comments. See example.)
|
Output |
|
//
//=====================================================================
//TextMaestro Technologies TM
//All rights reserved.
//=====================================================================
//
//
//* This module determines the insert location of text
//* for right-append feature.
//*
//
int CTextCvt::M_GetInsertLoc(CString
&temp)
{
int
len = temp.GetLength();
int
n=0;
n
= temp.ReverseFind(' '); //
"23423423423234234" case, no blank
if
(n<0) return 0;
if
(n==len-1){ //
"123213 23423
"
case, trailing blanks
while(1){
if
(temp.GetAt(n)==' ') n--; //
clip tail blanks
else
break;
}
temp
= temp.Mid(0, n);
}
n
= temp.ReverseFind(' '); //
"231234 23234"
case, get pre blank.
if
(n<0) n = 0; //
needed for "12312312 "
case.
return
n;
} |
Note that text within /*
and */ is to be transformed. Since
* needs to be a non-wild token in
Find, we could
not use it as a wild-card. Thereby, we selected @
as wild-card for Find
(you can select something else.) By defining Find
as /*@*/ we are basically getting
hold of a block of C-style comment, which may consist of multiple lines.
Once that text is assimilated, we clean it by ?@=//@
qualifier.
Recall, a singleton wild-card denotes one line of
the input text. Therefore, the ?@=//@
qualifier grabs each line of the comment text and inserts //
in the beginning of the line. Once again, this qualifier is cleansing
the argument which is holding the comment text at the moment, and it has
no effect outside of the comment block.
(d)
Align Argument Top
Using qualifier of the form <a=m> you can align text at m-th
column. Consider the following input:
|
Input |
|
InfoContact.htm TextCvt
InfoDownload.htm TextCvt
InfoExamplesRoot.htm TextCvt
InfoMessageBoard.htm FtpSupport
InfoPolicy.htm FtpSupport
InfoService.htm FtpSupport
InfoServiceMore.htm WorkSpace
InfoServiceMoreOrg.htm WorkSpace |
Using the following macro:
|
Find: |
*^b* |
|
Replace: |
Project:
<*2> <a=30> Module: <*1> |
we get this:
|
Output Column
30 |
|
|
Project:
TextCvt Module:
InfoContact.htm
Project:
TextCvt Module:
InfoDownload.htm
Project:
TextCvt Module:
InfoExamplesRoot.htm
Project:
FtpSupport Module:
InfoMessageBoard.htm
Project:
FtpSupport Module:
InfoPolicy.htm
Project:
FtpSupport Module:
InfoService.htm
Project:
WorkSpace Module:
InfoServiceMore.htm
Project:
WorkSpace Module:
InfoServiceMoreOrg.htm |
You can have multiple alignment qualifiers. In that
case behavior of the alignment qualifier can be tricky. As a rule of thumb,
alignment qualifier means move the current cursor position to m-th column
from the previous line break. Here is another example with multiple alignment
qualifiers in multi-line definition:
Consider the above input and the following macro
definition:
|
Find: |
*^b* |
|
Replace: |
#<a=67?.>
Reserve <*1> <a=33> /project=<*2> <a=55>
/nooutput
Replace <*1> <a=33> "08-Jan-2004"
<a=55> /user=admin |
This generates the following output:
|
Output |
|
#.................................................................
Reserve InfoContact.htm /project=TextCvt
/nooutput
Replace InfoContact.htm "08-Jan-2004"
/user=admin
#.................................................................
Reserve InfoDownload.htm /project=TextCvt
/nooutput
Replace InfoDownload.htm "08-Jan-2004"
/user=admin
#.................................................................
Reserve InfoExamplesRoot.htm /project=TextCvt
/nooutput
Replace InfoExamplesRoot.htm "08-Jan-2004"
/user=admin
#.................................................................
Reserve InfoMessageBoard.htm /project=FtpSupport
/nooutput
Replace InfoMessageBoard.htm "08-Jan-2004"
/user=admin
#.................................................................
Reserve InfoPolicy.htm /project=FtpSupport
/nooutput
Replace InfoPolicy.htm "08-Jan-2004"
/user=admin
#.................................................................
Reserve InfoService.htm /project=FtpSupport
/nooutput
Replace InfoService.htm "08-Jan-2004"
/user=admin
#.................................................................
Reserve InfoServiceMore.htm /project=WorkSpace
/nooutput
Replace InfoServiceMore.htm "08-Jan-2004"
/user=admin
#.................................................................
Reserve InfoServiceMoreOrg.htm /project=WorkSpace
/nooutput
Replace InfoServiceMoreOrg.htm "08-Jan-2004"
/user=admin |
Note the use of <a=67?.>
What it means is, move the cursor at column 67 from the previous line
break, and while doing so insert "." as the filling character.
Similar to the <a=m>
qualifier, there exists another option, in particular <A=m>.
While <a=m> performs a
left-justify effect for the next token, <A=m>
performs a right-justify effect for the previous token. For example, <*n> <A=40> <$n+1>
means insert filling character (default is blank) before
n-th token such that end of it
is aligned at 40-th column. Consider the same input and the following
macro definition:
|
Find: |
*^b* |
|
Replace: |
<*2><A=30?~>
<*1><a=60?.>10 |
This generates the following output:
|
Output |
|
~~~~~~~~~~~~~~~~~~~~~~TextCvt
InfoContact.htm..............10
~~~~~~~~~~~~~~~~~~~~~~TextCvt
InfoDownload.htm.............10
~~~~~~~~~~~~~~~~~~~~~~TextCvt
InfoExamplesRoot.htm.........10
~~~~~~~~~~~~~~~~~~~FtpSupport
InfoMessageBoard.htm.........10
~~~~~~~~~~~~~~~~~~~FtpSupport
InfoPolicy.htm...............10
~~~~~~~~~~~~~~~~~~~FtpSupport
InfoService.htm..............10
~~~~~~~~~~~~~~~~~~~~WorkSpace
InfoServiceMore.htm..........10 |
Note that the qualifier <A=30?~>
placed "~" before the token such that the end of the token is
aligned with 30-th column, giving it a right-justify look. The qualifier
<a=60?.> on the other hand
placed dots at the current position such that last dots in each line are
aligned with column 60, which led to the right-justified look for token
"10".
In addition, <a=-m?C>
allows you to place the cursor at next tab, where tab-width is of m characters,
using the filling character C. This is commonly used to replace tab (\t) with blank spaces.
(e)
Increment Argument Top
Using qualifier of the form <i=b> allows to place a numerical starting
with base b. Consider the following
input:
|
Input |
|
InfoTech_01_Program.htm
InfoTech_02_ToolbarMain.htm
InfoTech_03_TBSession.htm
InfoTech_04_TBFtp.htm
InfoTech_05_TBCvt.htm
InfoTech_06_SessMan.htm
InfoTech_07_FTPman.htm
InfoTech_08_FileAttr.htm
InfoTech_09_BrowseRm.htm
InfoTech_10_WorlPad.htm
InfoTech_11_CvtScheme.htm |
With the following macro definition:
|
Find: |
*^d_* |
|
Replace: |
<i=1>.
<A=8><*2> <a=45?.><i=10?5> |
we get the following output:
|
Output |
|
1.
Program.htm .........................10
2.
ToolbarMain.htm .....................15
3.
TBSession.htm .......................20
4.
TBFtp.htm ...........................25
5.
TBCvt.htm ...........................30
6.
SessMan.htm .........................35
7.
FTPman.htm ..........................40
8.
FileAttr.htm ........................45
9.
BrowseRm.htm ........................50
10.
WorlPad.htm .........................55
11.
CvtScheme.htm .......................60 |
Note that the increment offset is by default 1. A
qualifier of the form <i=b?N>
can be used where N denotes the offset. Above, the offset is 5 in <i=10?5>.
A qualifier of the form <i=b#N> can be used where
N denotes the width of the incremented value. Consider the following definition:
|
Find: |
*^d_* |
|
Replace: |
<i=1#2>. <*2> <a=45?.><i=10?5#4> |
Here is the output:
|
Output |
|
01.
Program.htm ..........................0010
02.
ToolbarMain.htm ......................0015
03.
TBSession.htm ........................0020
04.
TBFtp.htm ............................0025
05.
TBCvt.htm ............................0030
06.
SessMan.htm ..........................0035
07.
FTPman.htm ...........................0040
08.
FileAttr.htm .........................0045
09.
BrowseRm.htm .........................0050
10.
WorlPad.htm ..........................0055
11.
CvtScheme.htm ........................0060 |
Note the padding of 0's to make incremented values
of 2 digits and 4 digits.
Comments: Top
(1) Use Match
case: It is strongly recommended to have Match
case checked for a macro. A case-sensitive search can be as much
as 100 times faster than a non-case-sensitive search.
(2) Caution
on multi-line Find: Find
may consist of multiple lines. At the same time one can have Search
line-by-line checked. But that is contradictory. A Find
containing line-break will never be found if Search line-by-line is checked.
Because with Search line-by-line option checked, the parsing restarts
whenever a line-break is encountered. Therefore, you do not want to have
multi-line Find when Search
line-by-line is checked.
(3) Caution
on using <i=b> and <a=m> flags: If the input has any text
of the form <i=b> and <a=m>, then using these flags in Replace might not generate expected
results all the time.
(4) Using
library of macros: Each macro you define can be stored in a library.
When you click on the convert button from the library panel, you basically
execute the active macros of the library sequentially. Using a library
of macros on an input is a whole new level of muscle to flex.
(5)
Delimiters: The delimiter list may have only double delimiters.
A double delimiter is one that has begin and end parts.
Top |