Google Группы больше не поддерживают новые публикации и подписки в сети Usenet. Опубликованный ранее контент останется доступен.

Basic string manipulation

618 просмотров
Перейти к первому непрочитанному сообщению

Grod

не прочитано,
20 нояб. 2004 г., 08:04:1820.11.2004
I have used awk but do not have much experience with windows batch
and wondered how to accomplish the basic string manipulations
that I am used to:

1. Find the number of characters in a string.
e.g. if the string is banana then the answer is 6.

2. Find the n character long substring which starts at character position m.
e.g. if the string is banana and the m=2 and n=4 then the answer is anan

3. Find the substring that starts at character position m.
e.g. if the string is banana and m=2 then the answer is anana

4. Find the starting character position of the first occurrence of
a substring in a string.
e.g. if the string is banana and the substring is an then the answer is 2.

5. Replace the first occurrence of string s with string t in a given string.
e.g. if the given string is banana and s=an and t=zzz, the answer is bzzznana
[I know that if one wants to replace every occurrence one can do
this: set "s=%s:an=zzz%" but here we just want the first replaced.]

6. Split a given character string according to a separator character.
e.g. if the string is banana and the separator character is n then
the answer is the three strings: ba, a and a.

I would like to know how to do all of these directly in windows
batch without using an external program.

Thanks.

[P.S. I tried to post this yesterday but have not seen it appear so
I assume I did something wrong. Apologies if it appears twice.]

foxidrive

не прочитано,
20 нояб. 2004 г., 09:46:3720.11.2004
On 20 Nov 2004 05:04:18 -0800, Grod wrote:

Take a look at set in W2K or XP

set /?

ask any remaining questions after you've studied it.

Matthias Tacke

не прочитано,
20 нояб. 2004 г., 10:30:5820.11.2004
Grod schrieb:

> I have used awk but do not have much experience with windows batch
> and wondered how to accomplish the basic string manipulations
> that I am used to:
>
Hi grod,
2,3 are easy using set.
6 may be done with
for /f "tokens=1-3 delims=n" %%A in ("banana") do echo %%A %%B %%C

> 1. Find the number of characters in a string.
> e.g. if the string is banana then the answer is 6.
>

> 4. Find the starting character position of the first occurrence of
> a substring in a string.
> e.g. if the string is banana and the substring is an then the answer is 2.
>
> 5. Replace the first occurrence of string s with string t in a given string.
> e.g. if the given string is banana and s=an and t=zzz, the answer is bzzznana
> [I know that if one wants to replace every occurrence one can do
> this: set "s=%s:an=zzz%" but here we just want the first replaced.]
>

> I would like to know how to do all of these directly in windows
> batch without using an external program.
>

The other ones may be done with more complex combinations of set and
for.

BTW Most windows versions have wsh installed and the vbs commands to
use are 1. Len, 2.+3. Mid, 4. Instr, 5. RegExp, 6. Split

HTH

--
Gruesse Greetings Saludos Saluti Salutations
Matthias
---------+---------+---------+---------+---------+---------+---------+

Paul R. Sadowski [MVP]

не прочитано,
20 нояб. 2004 г., 13:00:5320.11.2004
Hello, Grod:
On 20 Nov 2004 05:04:18 -0800: you wrote...

G>
G> 1. Find the number of characters in a string.
G> e.g. if the string is banana then the answer is 6.
G>

http://www.paulsadowski.com/WSH/cmdutils.htm and scroll down to the bottom
of the page (StrLen)

Regards, Paul R. Sadowski [MVP].

--
Paul R. Sadowski
Microsoft MVP (MSN Client)
http://www.paulsadowski.com/


Ted Davis

не прочитано,
20 нояб. 2004 г., 13:08:4620.11.2004
On 20 Nov 2004 05:04:18 -0800, ggroth...@volcanomail.com (Grod)
wrote:

>I have used awk but do not have much experience with windows batch
>and wondered how to accomplish the basic string manipulations
>that I am used to:
>
>1. Find the number of characters in a string.
>e.g. if the string is banana then the answer is 6.
>
>2. Find the n character long substring which starts at character position m.
>e.g. if the string is banana and the m=2 and n=4 then the answer is anan
>
>3. Find the substring that starts at character position m.
>e.g. if the string is banana and m=2 then the answer is anana
>
>4. Find the starting character position of the first occurrence of
>a substring in a string.
>e.g. if the string is banana and the substring is an then the answer is 2.
>
>5. Replace the first occurrence of string s with string t in a given string.
>e.g. if the given string is banana and s=an and t=zzz, the answer is bzzznana
>[I know that if one wants to replace every occurrence one can do
>this: set "s=%s:an=zzz%" but here we just want the first replaced.]
>
>6. Split a given character string according to a separator character.
>e.g. if the string is banana and the separator character is n then
>the answer is the three strings: ba, a and a.
>
>I would like to know how to do all of these directly in windows
>batch without using an external program.
>

SET does 2 and 3 directly.

for /f "tokens=1,2,3,4,5,6,7 delims=n" %%A in ("banana") do echo %%A
%%B %%C %%D %%E %%F %%G

does #6, though crudely. If it were worth the effort, I would
construct a loop that used tokens=1,* to extract the first one as %%A
and then feed %%B back into the loop as often as needed to get the
rest. But I have gawk and place no pointless restrictions on what
tools I can use, so it isn't worth the effort.

5 can perhaps be accomplished in pure batch using the method just
described to separate fields, then splice them back together with the
delimiter, except for the first two. length() can be emulated several
ways - since I am still thinking loops, I would suggest a FOR /l
counter loop that used SET to replace substrings with ever growing
strings of a single unusual character until the resulting string and
the replacement string are identical - then the length of the
replacement string is the same os that of the original string, and
since the replacement string was generated by a counter, its length is
known.

The index() of a substring can be found several ways too, but keeping
in the same general line, the pattern can be replaced by an unusual
replacement string of identical characters, then that character used
in a FOR /f as delims to split off the portion ahead of the pattern,
the length of which gives the index() and can be determined as above
or with some simpler scheme that is outside my current line of
thought.

In the real world, we usually use better suited tools than batch
language for the things it doesn't do easily and use batch for those
for which it is best suited. I use a very rich tool kit that includes
gawk and many GNU utilities, the Cygwin environment, and for
administrative chores, several utility packages such as PsTools and
AINTX. I also make much use of Apache for several purposes.


--
T.E.D. (tda...@gearbox.maem.umr.edu)

Grod

не прочитано,
20 нояб. 2004 г., 21:39:1120.11.2004
> I have used awk but do not have much experience with windows batch
> and wondered how to accomplish the basic string manipulations
> that I am used to:

Thanks to everyone who responded. Here are the answers or pointers
to where the answers are and answers follow. Reference material
that may be helpful in this include the help command:
help set, help for, help goto, help call, help if are all useful.
Also the FAQ at:

ftp://garbo.uwasa.fi/pc/link/tscmd.zip

has useful information and just googling the archives of

alt.msdos.batch.nt

provides useful information.

>
> 1. Find the number of characters in a string.
> e.g. if the string is banana then the answer is 6.

See tscmd.zip (link is provided above) or look at the very bottom of:
http://www.paulsadowski.com/WSH/cmdutils.htm

>
> 2. Find the n character long substring which starts at character position m.
> e.g. if the string is banana and the m=2 and n=4 then the answer is anan

set mystring=banana
echo %mystring:~1,4%

>
> 3. Find the substring that starts at character position m.
> e.g. if the string is banana and m=2 then the answer is anana
>

set mystring=banana
echo %mystring:~1%

> 4. Find the starting character position of the first occurrence of
> a substring in a string.
> e.g. if the string is banana and the substring is an then the answer is 2.

See tscmd.zip (link is provided above).

>
> 5. Replace the first occurrence of string s with string t in a given string.
> e.g. if the given string is banana and s=an and t=zzz, the answer is bzzznana
> [I know that if one wants to replace every occurrence one can do
> this: set "s=%s:an=zzz%" but here we just want the first replaced.]

set mystring=banana
set post=%mystring:*an=%
call echo %%mystring:an%post%=%%zzz%post%

> 6. Split a given character string according to a separator character.
> e.g. if the string is banana and the separator character is n then
> the answer is the three strings: ba, a and a.

If the separator is whitespace then one can just call a subroutine
like this:

@echo off
setlocal
set "a=b c d e"
call :sub %a%
goto:eof
:sub
rem at this point the fields are in %1, %2, ...
rem we print them out as an example
:loop
if "%1"=="" goto:eof
echo "%1"
shift
goto:loop

Otherwise, we can work with general separator like this:

@echo off
setlocal
call :split banana n
rem Display result stored in x[1], ..., x[xlen]
for /l %%i in (1,1,%xlen%) do call echo Element %%i is %%x[%%i]%%
goto :eof

:split
set post=%1
set xlen=0
:loop
set s=%post%
set /a xlen+=1
call set post=%%s:*%2=%%
set post
call set x[%xlen%]=%%s:%2%post%=%%
set x[%xlen%]
if not "%s%"=="%post%" goto :loop
goto :eof

The following is a variation of the above that requires the separator
string to be a single character:

@echo off
setlocal
call :split banana n
rem Display result stored in x[1], ..., x[xlen]
for /l %%i in (1,1,%xlen%) do call echo Element %%i is %%x[%%i]%%
goto :eof

:split
set s=%1
set xlen=0
:loop
set /a xlen+=1
set post=%%s:*%2=%%
call set x[%xlen%]=%%s:%2%post%=%%
set s=%post%
if defined s goto loop
goto :eof

> I would like to know how to do all of these directly in windows
> batch without using an external program.

It seems that #2, #3 and #5 are pretty short but the rest are
more complex and involve looping.

Does anyone have any corrections, improvements, shorter special cases,
better approaches?

Also, think the main application of all this is argument processing
and I wonder if there is any argument processing code out there that
someone could point to?

Clay Calvert

не прочитано,
20 нояб. 2004 г., 22:07:1720.11.2004
On 20 Nov 2004 05:04:18 -0800, ggroth...@volcanomail.com (Grod)
wrote:

>5. Replace the first occurrence of string s with string t in a given string.


>e.g. if the given string is banana and s=an and t=zzz, the answer is bzzznana
>[I know that if one wants to replace every occurrence one can do
>this: set "s=%s:an=zzz%" but here we just want the first replaced.]

This is possible...

set str="banana"
set sub=zzz
set str=%str:an=ªº%
:: "ª" is alt-166 on number pad. "º" is alt-167
for /f "tokens=1* delims=ª" %%a in (%str%) do set str=%%a%sub%%%b
set str="%str:ª=an%"
set str=%str:º=%
for /f "tokens=*" %%a in (%str%) do echo %%~a

This even worked when the string contained redirection characters.
set str="b|an&an>a"

Clay Calvert
CCal...@Wanguru.com
Replace "W" with "L"

Clay Calvert

не прочитано,
21 нояб. 2004 г., 00:18:5521.11.2004
On 20 Nov 2004 18:39:11 -0800, ggroth...@volcanomail.com (Grod)
wrote:

>> 1. Find the number of characters in a string.
>> e.g. if the string is banana then the answer is 6.

Assuming a writable location, here is another option that will work in
2000, XP and newer.

echo %mystring%>StrLen.text
for %%a in (StrLen.text) do set /a StrLen=%%~za-2
echo %StrLen%

>> 4. Find the starting character position of the first occurrence of
>> a substring in a string.
>> e.g. if the string is banana and the substring is an then the answer is 2.

Based on what you had for 5, and also 1 above (2000,XP,+).
set mystring=banana
set Substr=%mystring:*an=%
call echo %%mystring:an%Substr%=%%>StrLen.text
for %%a in (StrLen.text) do set /a StrStart=%%~za-1
echo %StrStart%

>> 6. Split a given character string according to a separator character.
>> e.g. if the string is banana and the separator character is n then
>> the answer is the three strings: ba, a and a.

If you don't need to assign each string to a variable (2000,XP,+):

set str=banana
for %a in ("%str:n=" "%") do echo %~a

If you do want to assign each to a variable (2000,XP,+):

setlocal enabledelayedexpansion
set str=banana
set count=0
for %%a in ("%str:n=" "%") do set /a count+=1 & set Var!count!=%%~a
set var

Grod

не прочитано,
21 нояб. 2004 г., 10:32:1121.11.2004
Clay Calvert <ccal...@Wanguru.com> wrote in message news:<8420q09s399doouab...@4ax.com>...

> On 20 Nov 2004 18:39:11 -0800, ggroth...@volcanomail.com (Grod)
> wrote:
>
> >> 1. Find the number of characters in a string.
> >> e.g. if the string is banana then the answer is 6.
>
> Assuming a writable location, here is another option that will work in
> 2000, XP and newer.
>
> echo %mystring%>StrLen.text
> for %%a in (StrLen.text) do set /a StrLen=%%~za-2
> echo %StrLen%
>
> >> 4. Find the starting character position of the first occurrence of
> >> a substring in a string.
> >> e.g. if the string is banana and the substring is an then the answer is 2.
>
> Based on what you had for 5, and also 1 above (2000,XP,+).
> set mystring=banana
> set Substr=%mystring:*an=%
> call echo %%mystring:an%Substr%=%%>StrLen.text
> for %%a in (StrLen.text) do set /a StrStart=%%~za-1
> echo %StrStart%
>
> >> 6. Split a given character string according to a separator character.
> >> e.g. if the string is banana and the separator character is n then
> >> the answer is the three strings: ba, a and a.


Very nice.

Following up on your idea of placing the text in a file and
calculating the length of the file I got the following
solution which is longer than your solution but does avoid
having a named file by piping the string through findstr /o.

The portion within single quotes that begins on the second
line creates a file with the input string as line 1 and a
dot as line 2 but rather than store it explicitly, it pipes
that to findstr /o which prepends a numeric character offset
(relative to the beginning of the file) to each line and a
second findstr then removes the first line leaving the second
with its offset.

The outer for places that result, the offset from the second
and now only remaining line, into a variable, strlen, from
which we subtract 5 to take the quotes and end of line
characters into account. (I would have thought it should
have been 4 and not sure where the extra character comes
in but running it seems that it gives the right answer
with 5.)

set mystring=banana
for /f "tokens=1* delims=:" %%a in (
'^(for %%i in ^("%mystring%" .^) do @echo %%i^)
^| findstr /o .^| findstr /v /b 0') do set /a strlen=%%~a-5

As in your post, to get the character position of the first
match of an in banana we find the prefix to the substring
and then calculate the prefix's length except that here we
use the above code for length. This returns the number of
characters prior to the first match in strlen.

set mystring=banana
set sub=an

call set post=%%mystring:*%sub%=%%
call set pre=%%mystring:%sub%%post%=%%

rem calculate length of pre
for /f "tokens=1* delims=:" %%a in (
'^(for %%i in ^("%pre%" .^) do @echo %%i^)
^| findstr /o .^| findstr /v /b 0') do set /a strlen=%%~a-5

Clay Calvert

не прочитано,
22 нояб. 2004 г., 13:31:2522.11.2004
On 21 Nov 2004 07:32:11 -0800, ggroth...@volcanomail.com (Grod)
wrote:

>set mystring=banana


>set sub=an
>
>call set post=%%mystring:*%sub%=%%
>call set pre=%%mystring:%sub%%post%=%%
>
>rem calculate length of pre
>for /f "tokens=1* delims=:" %%a in (
> '^(for %%i in ^("%pre%" .^) do @echo %%i^)
> ^| findstr /o .^| findstr /v /b 0') do set /a strlen=%%~a-5

I am very impressed. That is a very clever technique, and I've never
seen a truly nested FOR loop before. Thank you for contributing to
this group.

Grod

не прочитано,
27 нояб. 2004 г., 12:16:0727.11.2004
ggroth...@volcanomail.com (Grod) wrote in message news:<ffd662ea.04112...@posting.google.com>...

I have a small improvement to this which involves eliminating the second
findstr and using skip=1 in the for instead. The reduction in length
means that the portion within single quotes can now be placed all on
the same line making it easier to read:

set mystring=banana
for /f "tokens=1* delims=: skip=1" %%a in (
'^(for %%i in ^("%mystring%" .^) do @echo %%i^) ^| findstr /o .'

foxidrive

не прочитано,
27 нояб. 2004 г., 16:22:1027.11.2004
On 27 Nov 2004 09:16:07 -0800, Grod wrote:

> I have a small improvement to this which involves eliminating the second
> findstr and using skip=1 in the for instead. The reduction in length
> means that the portion within single quotes can now be placed all on
> the same line making it easier to read:
>
> set mystring=banana
> for /f "tokens=1* delims=: skip=1" %%a in (
> '^(for %%i in ^("%mystring%" .^) do @echo %%i^) ^| findstr /o .'
> ) do set /a strlen=%%~a-5

This seems logical and neat... I spent an absorbed 1/2 hour dissecting the
routine myself, after Ted mentioned it, and it is quite a clever
construction.
The method of nesting seems to emulate the contents of a file rather than
two separate strings, in the usage above.

I'm unsure of the attributions in this thread, and just purged my
newsreader, but this technique seems to be your development. If so then
kudos and thanks for sharing it. :)

Clay Calvert

не прочитано,
27 нояб. 2004 г., 21:26:4527.11.2004
On 27 Nov 2004 09:16:07 -0800, ggroth...@volcanomail.com (Grod)
wrote:

>> set mystring=banana
>> set sub=an
>>
>> call set post=%%mystring:*%sub%=%%
>> call set pre=%%mystring:%sub%%post%=%%
>>
>> rem calculate length of pre
>> for /f "tokens=1* delims=:" %%a in (
>> '^(for %%i in ^("%pre%" .^) do @echo %%i^)
>> ^| findstr /o .^| findstr /v /b 0') do set /a strlen=%%~a-5
>
>I have a small improvement to this which involves eliminating the second
>findstr and using skip=1 in the for instead. The reduction in length
>means that the portion within single quotes can now be placed all on
>the same line making it easier to read:
>
>set mystring=banana
>for /f "tokens=1* delims=: skip=1" %%a in (
> '^(for %%i in ^("%mystring%" .^) do @echo %%i^) ^| findstr /o .'
> ) do set /a strlen=%%~a-5

I'm impressed.

Hey, since %%b is never referenced, the "tokens=1* " pobably isn't
needed since "tokens=1" is implied by default.

for /f "delims=: skip=1" %%a in (


'^(for %%i in ^("%mystring%" .^) do @echo %%i^) ^| findstr /o .'
) do set /a strlen=%%~a-5

Clay Calvert

Matthias Tacke

не прочитано,
28 нояб. 2004 г., 17:22:4628.11.2004
Clay Calvert schrieb:
>(Grod)wrote:

>>I have a small improvement to this which involves eliminating the second
>>findstr and using skip=1 in the for instead. The reduction in length
>>means that the portion within single quotes can now be placed all on
>>the same line making it easier to read:
>>
>>set mystring=banana
>>for /f "tokens=1* delims=: skip=1" %%a in (
>> '^(for %%i in ^("%mystring%" .^) do @echo %%i^) ^| findstr /o .'
>> ) do set /a strlen=%%~a-5
>
> I'm impressed.
>
> Hey, since %%b is never referenced, the "tokens=1* " pobably isn't
> needed since "tokens=1" is implied by default.
>
> for /f "delims=: skip=1" %%a in (
> '^(for %%i in ^("%mystring%" .^) do @echo %%i^) ^| findstr /o .'
> ) do set /a strlen=%%~a-5
>
Also my kudos to Grod, clever combination.

The skip=1 can also be omitted with findstr /x /o .

So a callable function with a wrapper.cmd could look like this:

::strlen.cmd:::::::::::::::::::::::::::::::::::::::::::::::::::::::::
@echo off@setlocal
set mystring=banana schoc ice
call :StrLen "%mystring%" Len
echo %mystring% %Len%
goto :Eof
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:StrLen "[quoted] string" by val LEN by ref
for /f "delims=:" %%A in (
'^(for %%C in ^("%~1" .^) do echo %%C^)^|findstr /x /o .'
) do set /A %2=%%~A-5
::strlen.cmd:::::::::::::::::::::::::::::::::::::::::::::::::::::::::

Grod

не прочитано,
29 нояб. 2004 г., 21:55:2129.11.2004
"Paul R. Sadowski [MVP]" <sado...@mvps.org> wrote in message news:<pDLnd.1057$Nh1.91@trnddc09>...

> Hello, Grod:
> On 20 Nov 2004 05:04:18 -0800: you wrote...
>
> G>
> G> 1. Find the number of characters in a string.
> G> e.g. if the string is banana then the answer is 6.
> G>
>
> http://www.paulsadowski.com/WSH/cmdutils.htm and scroll down to the bottom
> of the page (StrLen)
>

Thanks. Here is a minor variation which combines the
two if statements into one:

call :Length banana
echo %strLen%
goto:eof

:Length
setlocal & set strLen=0 & set ss=%*
:loop
if defined ss (set /a strLen+=1 & set ss=%ss:~1%
goto:loop)
endlocal & set strLen=%strLen%
goto:eof

Paul R. Sadowski [MVP]

не прочитано,
30 нояб. 2004 г., 09:56:3130.11.2004
Hello, Grod:
On 29 Nov 2004 18:55:21 -0800: you wrote...

G> Thanks. Here is a minor variation which combines the
G> two if statements into one:
G>
G> call :Length banana
G> echo %strLen%
G> goto:eof
G>

Thanks.

0 новых сообщений