简体   繁体   English

如何在不丢失空格的情况下拆分变量中的字符串?

[英]How to split string in a variable without loosing spaces?

how can i split the string 我怎么能分裂字符串

"   This  is  a text  with  spaces    "

that is in the variable "string" into text parts without loosing the spaces ? 那是在变量“string”中的文本部分而没有丢失空格?

set string="#   This  is  a text  with  spaces    #"

should be split into 应分成

"#   This"
"  is"
"  a"
" text"
"  with"
"  spaces    #"

Using For /F "delims= " ... doesn't work because it eliminates all spaces. 使用For /F "delims= " ...不起作用,因为它消除了所有空格。

Is there a 'simple' solution or can anyone explain how to parse the string character by character so i can count up spaces to first character, then read all characters until next space and write the counted spaces and the read characters together to a new/temp variable ?? 有一个'简单'的解决方案或任何人都可以解释如何逐字符解析字符串,这样我可以计算第一个字符的空格,然后读取所有字符直到下一个空格,并将计数的空格和读取的字符一起写入一个新的/临时变量??

thanks 谢谢

Yeah, I don't really understand the # either. 是的,我不太了解#也。 What is it about " spaces #" that makes it hold onto the trailing spaces, while all other elements keep the preceding but not the proceeding spaces? 什么是“空间#”使它保持在尾随空格,而所有其他元素保持前面但不是前进的空格?

Oh, well, effort spent in asking = effort spent in answering. 哦,好吧,努力花在询问=花在回答上的努力。 Do with this what you will. 做到这一点,你会做什么。

@if (@a==@b) @end /*

:: batch portion

@echo off
setlocal

call :split "#   This  is  a text  with  spaces    #"
exit /b

:split <string>
cscript /nologo /e:jscript "%~f0" "%~1"
goto :EOF

:: JScript portion */
WSH.Echo(WSH.Arguments(0).match(/\s*\S+/g).join('\n'));

Output: 输出:

#
   This
  is
  a
 text
  with
  spaces
    #

Update 更新

If you want the first + second, and the penultimate + ultimate elements joined, modify the JScript portion of the above script as follows: 如果您想要第一个+第二个,并且倒数第二个+终极元素已连接,请修改上述脚本的JScript部分,如下所示:

:: JScript portion */
var m = WSH.Arguments(0).match(/\s*\S+/g);
m[0] = m.shift() + m[0];
m[m.length - 2] += m.pop();
WSH.Echo(m.join('\n'));

Output: 输出:

#   This
  is
  a
 text
  with
  spaces    #

And if you want each element enclosed in quotation marks, change the last line as follows: 如果您希望每个元素都用引号括起来,请更改最后一行,如下所示:

    WSH.Echo('"' + m.join('"\n"') + '"');

Output: 输出:

"#   This"
"  is"
"  a"
" text"
"  with"
"  spaces    #"

I don't see a simple solution in batch, though of course if you can consider powershell or javascript you'll be working with a more appropriate toolset for string manipulation. 我没有批量看到一个简单的解决方案,当然如果你可以考虑使用powershell或javascript,你将使用更合适的字符串操作工具集。

Sticking with the batch requirement, you can loop through character by character and "collect" your words with something like this: 坚持批量要求,你可以逐个字符地循环,并用这样的东西“收集”你的单词:

@echo off
setlocal enabledelayedexpansion

set "string=   This  is  a text  with  spaces    "

set idx=0
set "word="
set "char="
set "lastchar= "
:loop
if "!string:~%idx%!" equ "" goto :eof
set char=!string:~%idx%,1!
if "%char%" equ " " (
    if "%lastchar%" neq " " (
        echo [%word%]
        set word=%char%
    ) else (
        set word=%word%%char%
    )
) else (
    set word=%word%%char%
)
set lastchar=%char%
set /a idx=%idx%+1
goto loop

This script uses batch's substring feature !string:~%idx%,1 to grab a single character from the string, incrementing idx with each loop. 此脚本使用批处理的子字符串功能!string:~%idx%,1从字符串中获取单个字符,每个循环递增idx Then it's just a matter of processing the word ( echo in this example) when the previous character was not a space and the current one is. 然后,当前一个字符不是空格而当前字符不是空格时,只需要处理单词(本例中为echo )。

This writes out: 这写道:

[   This]
[  is]
[  a]
[ text]
[  with]
[  spaces]

Note that I'm ignoring the # you had in your example because I don't understand where they fit in. 请注意,我忽略了您在示例中的# ,因为我不明白它们适合的位置。

the trick is substituting the contiguous spaces by just one space and the rest by some arbitrary character. 诀窍是用一个空格代替连续的空格,其余用一些任意的字符代替。 Assuming your string does not contain # s and that there are no more than 9 contiguous spaces, you can try this 假设你的字符串不包含# s以及有不超过9个连续的空间,你可以试试这个

set st=%st:         = ########%
set st=%st:        = #######%
set st=%st:       = ######%
set st=%st:      = #####%
set st=%st:     = ####%
set st=%st:    = ###%
set st=%st:   = ##%
set st=%st:  = #%

then you may parse with for /f and substitute back your # s by spaces 然后你可以用解析for /f和替换回你#通过空间S.

setlocal enabledelayedexpansion
for /f %%a in ("%st%") do (
  set ss= %%a
  echo !ss:#= !
)  

note that set inside the parentheses block requires you to enable delayed expansion and to use the ! 请注意,在括号内set要求您启用延迟扩展并使用! syntax (see HELP SET ) 语法(参见HELP SET

But this technique will only extract the first substring. 但是这种技术只会提取第一个子串。 To generalize, you need another trick, that is substituting the spaces into newlines so that the for /f will loop kinda line by line 为了概括,你需要另一个技巧,即将空格替换为换行符,以便for /f将逐行循环

note that in order to obtain a newline char you need to preserve the two blank lines after the set command 请注意,为了获取换行符,您需要在set命令后保留两个空行

set nl=^


rem continue two lines down....
for /f %%a in ("%st: =!nl!%") do (
  set ss= %%a
  set ss=!ss:#= !
  echo [!ss!]
)  

Try this: 尝试这个:

@echo off &setlocal enabledelayedexpansion
set "string=#   This  is  a text  with  spaces    #"

set string1=%string%
for %%i in (%string%) do (
    set string1=!string1: %%i = "%%i" !
    set /a strings+=1
)
set string1=#"%string1:~1,-1%"#
set string1=%string1:"= "%
for %%i in (%string1%) do (
    set /a count+=1
    set string2=%%i
    set string2=!string2: "=!
    set string2=!string2:"=!
    if !count! equ 2 (
     set $s1=!$s1!!string2!
    )else if !count! equ %strings% (
        set /a count-=1
        call set $s!count!=%%$s!count!%%!string2!
        ) else set $s!count!=!string2!
)
for /f "tokens=1*delims==" %%i in ('set "$s"') do echo "%%j"    

Output: 输出:

"#   This"
"  is"
"  a"
" text"
"  with"
"  spaces    #"

If I had to accomplish this obscure task, I would use a hybrid JScript/batch technique like in rojo's answer . 如果我必须完成这个不起眼的任务,我会使用像rojo的答案那样的混合JScript /批处理技术。 However, I would use a REPL.BAT utility that I have already written . 但是,我会使用我已编写REPL.BAT实用程序 Assuming my REPL.BAT is in either the current folder, or else somewhere in the PATH, then the following will work: 假设我的REPL.BAT位于当前文件夹中,或者位于PATH中的某个位置,则以下内容将起作用:

@echo off
setlocal enableDelayedExpansion
set "string=#   This  is  a text  with  spaces    #"

:: Build an "array" of text parts
set cnt=0
for /f delims^=^ eol^= %%A in ('repl "([^ ])(?= )" "$1\n" xs string') do (
  set /a cnt+=1
  set "string!cnt!=%%A"
)

:: Print the array values
for /l %%N in (1 1 %cnt%) do echo string%%N=[!string%%N!]

But if I wanted a pure batch solution, I would use the fairly efficient method below: 但如果我想要一个纯批处理解决方案,我会使用下面相当有效的方法:

@echo off
setlocal enableDelayedExpansion
set "string=#   This  is  a text  with  spaces    #"

:: Define LF to contain a single line feed character (0x0A)
set LF=^


:: Above 2 blank lines are critical - DO NOT REMOVE


:: Insert a line feed before every space
for %%n in ("!LF!") do set "string=!string: =%%~n !"

:loop  Remove line feeds sandwiched by spaces
for %%n in ("!LF!") do set "string2=!string: %%~n =  !"
if "!string2!" neq "!string!" (
  set "string=!string2!"
  goto :loop
)

:: Build an "array" of text parts: FOR /F splits the string at line feeds
set /a cnt=0
for /f delims^=^ eol^= %%A in ("!string!") do (
  set /a cnt+=1
  set "string!cnt!=%%A"
)

:: Print out the array values
for /l %%N in (1 1 %cnt%) do echo string%%N=[!string%%N!]

Both solutions above give the following output: 以上两种解决方案都提供以下输出:

string1=[#]
string2=[   This]
string3=[  is]
string4=[  a]
string5=[ text]
string6=[  with]
string7=[  spaces]
string8=[    #]

Note that the FOR loop %%A expansion will corrupt the results if the string contains ! 请注意,如果字符串包含FOR循环%%A扩展将破坏结果! due to delayed expansion. 由于推迟扩张。 This limitation can be eliminated with additional coding. 通过额外的编码可以消除这种限制。 All the other posted solutions that use a FOR loop suffer from this same limitation. 所有其他使用FOR循环的已发布解决方案都受到同样的限制。 (at least they did when I wrote this) (至少我写这篇文章的时候他们这么做了)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM