String 批处理获取具有特殊字符的字符串长度

String 批处理获取具有特殊字符的字符串长度,string,batch-file,special-characters,readfile,string-length,String,Batch File,Special Characters,Readfile,String Length,我有一个包含两列文本的文件。使用批处理文件,我想提取第二列文本并获得字符串长度,然后将字符串长度和字符串文本写入输出文件。挑战我的步骤是确定具有特殊字符的字符串长度。例如,输入文件如下所示: escitalopram CN(C)CCC[C@@]1(C2=C(CO1)C=C(C=C2)C#N)C3=CC=C(C=C3)F ibuprofen CC(C)CC1=CC=C(C=C1)C(C)C(=O)O keflex CC1=C(N2[C@@H]([C@@H](C2=O)NC(=O)[C@@H](C3

我有一个包含两列文本的文件。使用批处理文件,我想提取第二列文本并获得字符串长度,然后将字符串长度和字符串文本写入输出文件。挑战我的步骤是确定具有特殊字符的字符串长度。例如,输入文件如下所示:

escitalopram CN(C)CCC[C@@]1(C2=C(CO1)C=C(C=C2)C#N)C3=CC=C(C=C3)F ibuprofen CC(C)CC1=CC=C(C=C1)C(C)C(=O)O keflex CC1=C(N2[C@@H]([C@@H](C2=O)NC(=O)[C@@H](C3=CC=CC=C3)N)SC1)C(=O)O aspirin CC(=O)OC1=CC=CC=C1C(=O)O linoleic_acid CCCCC/C=C\C/C=C\CCCCCCCC(=O)O
@echo off
setLocal EnableDelayedExpansion enableextensions


set arg1=%1

FOR /F "tokens=1,2 delims= " %%r IN (%1) DO (
set teststring="%%s"
echo "Passing     " %%s
call :GetStrLength %%s
echo.%%s
goto :EOF
)
  ::========================
  :GetStrLength
  setlocal enableextensions

set s=%1
echo " counting.... " %1

:: Get the length of the quoted string assuming a max of 255
set charCount=0
for /l %%c in (0,1,255) do (
  set si=!s:~%%c!
  if defined si set /a charCount+=1)
if %charCount% EQU 256 set charCount=0
echo The length of "%s%" is %charCount% characters
endlocal & goto :EOF

如果您有任何帮助,我们将不胜感激。

为了获得字符串的长度,我发现这个方法非常有效

@echo off
setLocal EnableDelayedExpansion

set s=%*
set length=0

:count
if defined s (
    if "!s:~0,1!" NEQ "@" if "!s:~0,1!" NEQ "/" if "!s:~0,1!" NEQ "\" set /A length += 1
    set "s=%s:~1%"
    goto count
)

echo %length%
@ECHO关闭
SETLOCAL
对于/f“tokens=1*delims=“%%a IN(q21817684.txt)DO(
设置/a计数=0
设置“化学=%%a”
设置“公式=%%b”
电话:报告
)
后藤:EOF
:报告
设置“公式=%formula:@=%”
设置“公式=%formula:\=%”
设置“公式=%formula://=%”
:reportl
如果定义公式(
设置“公式=%formula:~1%”
设置/a计数+=1
后藤报道
)
回显%化学%%count%
后藤:eof
我在测试中使用了一个名为
q21817684.txt
的文件。Yor数据在keflex和aspirin公式后有一个尾随空格。我在测试中排除了这一点,但增加了

SET "formula=%formula: =%"

显然,应该是等效的。

可以使用strlen函数,但应该使用byre而不是byval参数

此函数可以处理任何字符串,它始终需要13个循环来确定长度。
由于批处理中的变量可以包含不超过8191个字符,因此这就足够了

echo off
set "myString=Any content"
call :strlen result myString
echo %result%
exit /b

:strlen <resultVar> <stringVar>
(   
    setlocal EnableDelayedExpansion
    set "s=!%~2!#"
    set "len=0"
    for %%P in (4096 2048 1024 512 256 128 64 32 16 8 4 2 1) do (
        if "!s:~%%P,1!" NEQ "" ( 
            set /a "len+=%%P"
            set "s=!s:~%%P!"
        )
    )
)
( 
    endlocal
    set "%~1=%len%"
    exit /b
)
echo关闭
设置“myString=任何内容”
调用:strlen result myString
回显%结果%
退出/b
:斯特伦
(   
setlocal EnableDelayedExpansion
设置“s=!%~2!#”
设置“len=0”
对于%%P in(4096 2048 1024 512 256 128 64 32 16 8 4 2 1),请执行以下操作(
如果“!s:~%%P,1!”NEQ”“(
设置/a“len+=%%P”
集合“s=!s:~%%P!”
)
)
)
( 
端部
设置“%~1=%len%”
退出/b
)

由于未引用
=
而导致问题,批处理解析器将
=
视为令牌分隔符。当您传递一个包含
=
的无引号字符串作为参数时,该字符串在每个
=
处被分解为多个参数。应该可以通过添加一些策略性的引号来修复代码,还可以根据需要使用
~
参数扩展修饰符来删除封闭的引号。这不是一个通用的解决方案,但它应该适用于您的情况,因为我认为SMILES字符串永远不会包含
字符。请注意,包含引号的带引号字符串将包含字符串中实际上未被引用的部分

这是您的代码修复。我已经删除了一些不必要的代码和一些诊断消息

@echo off
setlocal

FOR /F "tokens=1,2 delims= " %%r IN (%1) DO (
  echo Passing     "%%s"
  call :GetStrLength "%%s"
  goto :EOF
)

::========================
:GetStrLength
setlocal enableDelayedExpansion

set "s=%~1"
echo counting.... %1

:: Get the length of the quoted string assuming a max of 255
set charCount=0
for /l %%c in (0,1,255) do (
  set si=!s:~%%c!
  if defined si set /a charCount+=1
)
if %charCount% EQU 256 set charCount=0
echo The length of "%s%" is %charCount% characters
endlocal & goto :EOF
下面是一个完整的工作脚本,它在删除立体化学字符后计算每个微笑字符串的长度。(我很好奇你为什么想要这个值)。它在jeb的回答中使用了一个修正版的极快strlen函数。我在初始FOR/F循环中添加了USEBACKQ选项,以防用户传递包含空格的带引号的文件名

@echo off
setlocal enableDelayedExpansion

for /f "usebackq tokens=1,2 delims= " %%A IN (%1) do (
  set "SMILES=%%B"
  for %%C in (@ / \) do set "SMILES=!SMILES:%%C=!"
  call :strlen len SMILES
  echo %%A !len!
)
exit /b

:strlen <resultVar> <stringVar>
setlocal enableDelayedExpansion
set "s=!%~2!#"
set "len=0"
for %%P in (4096 2048 1024 512 256 128 64 32 16 8 4 2 1) do (
  if "!s:~%%P,1!" NEQ "" (
    set /a "len+=%%P"
    set "s=!s:~%%P!"
  )
)
endlocal&set "%~1=%len%"
exit /b
@echo关闭
setlocal enableDelayedExpansion
对于/f“usebackq令牌=1,2 delims=“%A IN(%1)do(
设置“微笑=%%B”
对于(@/\)中的%%C,请设置“微笑=!微笑:%%C=!”
电话:斯特伦·莱恩·斯迈尔斯
回声%%A!len!
)
退出/b
:斯特伦
setlocal enableDelayedExpansion
设置“s=!%~2!#"
设置“len=0”
对于%%P in(4096 2048 1024 512 256 128 64 32 16 8 4 2 1),请执行以下操作(
如果“!s:~%%P,1!”NEQ”(
设置/a“len+=%%P”
集合“s=!s:~%%P!”
)
)
endlocal&设置“%~1=%len%”
退出/b

字符串长度工作正常-将参数传递到子线程时出现问题。如果不使用子例程而只是将字符串长度内联,会发生什么情况?尝试使用
call:GetStrLength“%%s“
设置s=%~1
,使参数表quoted@JerryJeremiah不,您不能以这种方式处理所有可能的字符串,调用将按值打断参数。您需要使用by-reference.Cool-SMILES字符串。我已经很久没有使用过这些工具了:-)这对OP询问的输入不起作用。当使用
输入时,此方法失败
=
,OP没有要求排除。此外,此方法对OP要求从计数中排除的
@
`和
/`进行计数。@我将努力使其排除这些字符,您是否有任何建议使其包括
=
?它现在将不包括这些字符。我很抱歉没有仔细阅读这个问题。它还包括
=
,但不包括
。此strlen方法将比OP方法慢得多,因为向后GOTOs将始终读取每个字符的完整文件。Oops-您对
s
的初始分配缺少关键延迟扩展:
集“s=!%~2#!
@dbenham你说得对,我错过了最重要的部分。脚本按照承诺的那样工作,所以谢谢。您可以识别微笑字符串以及立体化学符号。正如您所理解的,微笑字符串的长度本身没有什么价值。然而,我希望今后能够在此基础上再接再厉。
@echo off
setlocal enableDelayedExpansion

for /f "usebackq tokens=1,2 delims= " %%A IN (%1) do (
  set "SMILES=%%B"
  for %%C in (@ / \) do set "SMILES=!SMILES:%%C=!"
  call :strlen len SMILES
  echo %%A !len!
)
exit /b

:strlen <resultVar> <stringVar>
setlocal enableDelayedExpansion
set "s=!%~2!#"
set "len=0"
for %%P in (4096 2048 1024 512 256 128 64 32 16 8 4 2 1) do (
  if "!s:~%%P,1!" NEQ "" (
    set /a "len+=%%P"
    set "s=!s:~%%P!"
  )
)
endlocal&set "%~1=%len%"
exit /b