【问题标题】:batch get string length with special characters批量获取带有特殊字符的字符串长度
【发布时间】:2014-02-16 22:38:00
【问题描述】:

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

依他普仑 CN(C)CCC[C@@]1(C2=C(CO1)C=C(C=C2)C#N)C3=CC=C(C=C3)F 布洛芬CC(C)CC1=CC=C(C=C1)C(C)C(=O)O 凯弗莱CC1=C(N2[C@@H]([C@@H](C2=O)NC(=O)[C@@H](C3=CC=CC=C3)N)SC1)C( =O)O 阿司匹林 CC(=O)OC1=CC=CC=C1C(=O)O 亚油酸CCCCC/C=C\C/C=C\CCCCCCCC(=O)O

我可以使用批处理命令行和参数 %1 读取提取两个令牌的文件。我已经尝试了一些我在讨论组中找到的子程序,但我无法让它们工作。 “=”符号和其他特殊字符可能会导致问题。我正在寻找一种可以产生类似输出文件的解决方案。忽略“@”、“/”和“\”符号:

依他普仑 49 布洛芬 29 凯弗莱克斯 58 阿司匹林 24 亚油酸 25

到目前为止,我的程序如下所示:

@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

任何帮助将不胜感激。

【问题讨论】:

  • 字符串长度工作正常 - 将参数传递给子程序被破坏。如果您不使用子例程而只是将字符串长度内联会发生什么?
  • 尝试只使用call :GetStrLength "%%s"set s=%~1 以便引用参数
  • @JerryJeremiah 不,您不能以这种方式处理所有可能的字符串,CALL 将按值破坏参数。您需要使用引用。
  • 酷 - 微笑字符串。我已经很久没有和那些人一起工作了:-)

标签: string batch-file special-characters readfile string-length


【解决方案1】:

你可以使用 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
)

【讨论】:

  • 糟糕 - 您对 s 的初始分配缺少关键的延迟扩展:set "s=!%~2#!
  • @dbenham 你说得对,我错过了最重要的部分
【解决方案2】:

= 会导致问题,因为它没有被引用,并且批处理解析器将 = 视为标记分隔符。当您将包含= 的不带引号的字符串作为参数传递时,该字符串在每个= 处被分解为多个参数。应该可以通过添加一些策略性放置的引号以及使用~ 参数扩展修饰符来根据需要删除封闭引号来修复您的代码。这不是一个通用的解决方案,但它应该适用于您的情况,因为我认为 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

下面是一个完整的脚本,它在删除立体化学字符后计算每个 SMILES 字符串的长度。 (我很好奇你为什么想要那个值)。它在 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

【讨论】:

  • 脚本按承诺工作,非常感谢。您认出了 SMILES 字符串以及立体化学符号。如您所见,SMILES 字符串的长度本身并没有什么价值。但是,我希望将来能够在此基础上再接再厉。
【解决方案3】:

要获取字符串的长度,我发现following method 非常有效。

@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%

【讨论】:

  • 这不适用于 OP 询问的输入。
  • 此方法在输入!= 时失败,OP 并未要求排除。此外,此方法确实计算 OP 要求从计数中排除的 @` and /`。
  • @Monacraft 我会努力让它排除这些字符,你有什么建议让它包括!=
  • 它现在不会包含这些字符。我很抱歉没有仔细阅读这个问题。
  • 它还包括=,但不包括!
【解决方案4】:
@ECHO OFF
SETLOCAL
FOR /f "tokens=1*delims= " %%a IN (q21817684.txt) DO (
 SET /a count=0
 SET "chemical=%%a"
 SET "formula=%%b"
 CALL :report
)
GOTO :EOF

:report
SET "formula=%formula:@=%"
SET "formula=%formula:\=%"
SET "formula=%formula:/=%"
:reportl
IF DEFINED formula (
 SET "formula=%formula:~1%"
 SET /a count +=1
 GOTO reportl
)
ECHO %chemical% %count%

GOTO :eof

我使用了一个名为 q21817684.txt 的文件进行测试。 Yor 数据在 keflex 和 aspirin 的公式后有一个尾随空格。我为我的测试消除了它,但添加了

SET "formula=%formula: =%"

显然应该是等价的。

【讨论】:

  • 这种 strlen 方法将比 OP 的方法慢得多,因为向后 GOTO 将始终读取完整的文件,每个字符
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-22
  • 2020-07-26
  • 1970-01-01
  • 2020-07-12
相关资源
最近更新 更多