【问题标题】:Regular expressions to delete things from the first line in multiple txt files从多个txt文件的第一行删除内容的正则表达式
【发布时间】:2023-03-15 23:20:02
【问题描述】:

我在互联网上搜索了几天试图自己解决这个问题,但没有成功。我无法显示任何代码,因为我尝试的一切都是错误的。所以我的问题可能有点长,但我希望有人可以帮助我。

我有一个文件夹,其中包含大量带有抓取数据 (1000+) 的 .txt 文件。现在我想要一个循环遍历所有这些文件的脚本,更改第一行,然后再次保存文件。在.txt 文件的第一行,有一个标题。但我希望从该标题中删除某些内容。以下是来自 5 个不同 .txt 文件的一些第一行示例

Hello world my name is awesome, but you knew that video c5
Hello world my name is awesome  video3 v: Everybody knows I am r
Hello world my name is awesome: It got 100 likes in 10 min 1f
Hello world my name is awesome 43 video 2: Did you know that:
Hello world my name is awesome a3: It is Mr smokealot 1f,

我想我涵盖了所有可能的组合。我想要的是只有这部分Hello world my name is awesome 保留在第一行的每个文件中,其余部分必须删除。我还在.txt 文件的其他行上得到了文本,但这些必须保持不变。每个.txt 文件的每个标题都不同,但我使用Hello world my name is awesome 显示第一行的哪个部分包含标题。

我认为这些是为我修复标题所必须做的事情。

  1. 删除第一个逗号或冒号后的所有字符,包括逗号和冒号本身。
  2. 删除所有包含数字的单词和字母,如第五个第一行示例中的 a3。
  3. 删除所有号码。
  4. 删除单词视频。
  5. 删除除字母“I”之外的所有单个字符。这是从第二个第一行示例
  6. 中删除“v”

完成后,我想用当前名称将文件保存在当前位置。

这可能吗?

【问题讨论】:

  • 要保留的字符串是如何定义的?结果会是每个目标文本文件都有相同的第一行吗?
  • 如果所有标题都不同,我们怎么知道要保留什么,要删除什么?
  • @Magoo 不,每一行都是不同的。因为所有的标题都不一样。
  • @Squashman 几乎每个标题都以逗号或冒号结尾。因此,必须删除此右侧的所有内容。然后还有数字和带数字的单词需要删除。
  • @rojo 当我运行该行时,它给了我很多错误。命令中可能有错字吗?或者我做错了什么?我只想保留Hello world my name is awesome。我希望我可以重新刮掉它,但它是由程序完成的,我无法改变它

标签: regex windows powershell batch-file


【解决方案1】:

对批处理的 REGEX 支持非常有限(仅在 findstr 中实现,但很小的子集)。所以让我们(几乎)不使用 REGEX:

@echo off
setlocal enabledelayedexpansion
REM t.txt contains your first-line-examples
for /f "delims=" %%a in (t.txt) do call :getTitle %%a

goto :eof

:getTitle
set title=%*
REM get rid of all characters after (including) comma or colon:
for /f "delims=,:" %%a in ("%title%") do set title=%%a

REM get rid of every word with numbers and anything after it:
set "line="
for %%a in (%title%) do (
  REM if the word contains a number, Exit the Loop, else add the word to the line:
  echo %%a|findstr "[0-9]" >nul && goto :endOfTitle ||set line=!line! %%a
  )
:endOfTitle

REM get rid of the leading space (included with the SET in the last FOR)
if defined line set line=%line:~1%

echo(%line%

t.txt 的内容:

Hello world my name is awesome, but you knew that video c5
Hello world my name is awesome  video3 v: Everybody knows I am r
Hello world my name is awesome: It got 100 likes in 10 min 1f
Hello world my name is awesome 43 video 2: Did you know that:
Hello world my name is awesome a3: It is Mr smokealot 1f,
Hello world my name is John Doe, but you knew that video5c
Hello world my name is Jane Doe  video3v: but you knew that
Hello world my name is Superman: but you knew that 1f
Hello world my name is Asterix, Gallier 43: but you knew that 1f
34: this is obviously an invalid title
Any string is a title until it hits a comma or colon, this is scrap
Any word that contains a number ends the title l1ke this one

输出:

Hello world my name is awesome
Hello world my name is awesome
Hello world my name is awesome
Hello world my name is awesome
Hello world my name is awesome
Hello world my name is John Doe
Hello world my name is Jane Doe
Hello world my name is Superman
Hello world my name is Asterix

Any string is a title until it hits a comma or colon
Any word that contains a number ends the title

(@Mofi:我包括了你的一些例子——我喜欢这些名字:))

EDIT 处理当前文件夹中的所有文件

@echo off
setlocal enabledelayedexpansion

REM for all .txt files in the current folder do:
for /f "delims=" %%a in ('dir /b *.txt') do call :process "%%a"
goto :eof

:process
set file=%1
REM get first line of this file:
set /p first=<%1

REM 
call :getTitle %first%

REM when %line% is empty, skip the edit:
if defined line (
  echo %line% >"%~n1.tmp"
  more +1 %file% >>"%~n1.tmp"
  @ECHO move /y "%~n1.tmp" "%file%"
)
goto :eof

:getTitle
set title=%*

REM get rid of all characters after (including) comma or colon:
for /f "delims=,:" %%a in ("%title%") do set title=%%a

REM get rid of every word with numbers and anything after it:
set "line="
for %%a in (%title%) do (
  REM if the word contains a number, Exit the Loop, else add the word to the line:
  echo %%a|findstr "[0-9]" >nul && goto :endOfTitle ||set line=!line! %%a
  )
:endOfTitle

REM get rid of the leading space (included with the SET in the last FOR):
if defined line set line=%line:~1%

goto :eof

如果您对输出感到满意,请删除@ECHO

【讨论】:

  • @Mofi 对此有一个很好的转折。我现在差不多了。我只错过了一部分。那就是让这个脚本遍历一个包含很多.txt 文件的文件夹,然后更改第一行以仅保留标题,然后以与之前相同的名称保存.txt 文件。我自己试过了。但这对我来说太难了。如果您或其他人可以帮助我,我将不胜感激。如果没有,我理解。感谢您到目前为止的帮助
  • @Stephan 很高兴您回答第二个问题,即如何在您的答案中对目录中的所有文本文件使用子例程 GetTitle。我为这项额外的工作+1,非常智能的编码文件循环。
【解决方案2】:

我创建了文本文件Test.txt,内容如下:

Hello world my name is John Doe, but you knew that video5c
Hello world my name is Jane Doe  video3v: but you knew that
Hello world my name is Superman: but you knew that 1f
Hello world my name is Asterix, Gallier 43: but you knew that 1f
34: but you knew that this is an invalid title
, but you knew that this is also an invalid title
 but you knew that this is an invalid title, too

然后我开发了以下注释批处理文件来评估所有标题行:

@echo off
setlocal EnableDelayedExpansion
set "FileTitle="
for /F "usebackq delims=" %%L in ("Test.txt") do (
    call :GetTitle "%%L"
    echo Get from  "%%L"
    echo the title "!FileTitle!"
    echo.
)
endlocal
goto :EOF

:GetTitle
set "Line=%~1"

rem Replace the string " but you knew that" case insensitive
rem by character # with a comma before which is always removed.

set "Line=%Line: but you knew that=,#%"

rem Use character # as separator to get everything left of this character.

for /F "tokens=1 delims=#" %%T in ("%Line%") do set "FileTitle=%%T"
if "%FileTitle%" == "," goto TitleError
set "FileTitle=%FileTitle:~0,-1%"

:RemoveSpaces
if "%FileTitle%" == "" goto TitleError
if "%FileTitle:~-1%" == " " set "FileTitle=%FileTitle:~0,-1%" & goto RemoveSpaces

rem Is the last character a comma, remove this character, too.

if "%FileTitle:~-1%" == "," (
    set "FileTitle=%FileTitle:~0,-1%"
    if "!FileTitle!" == "" goto TitleError
    goto RemoveSpaces
)

rem Is the last character not a colon, we have the file title.

if not "%FileTitle:~-1%" == ":" goto :EOF

rem Otherwise remove the colon and the word left to the
rem colon if this word contains also at least 1 digit.

set "FileTitle=%FileTitle:~0,-1%"
set "LastWord="

rem The first condition in code below should be never true according to
rem provided sample data, but it is necessary to avoid an endless loop.

:RemoveWord
if "%FileTitle%" == "" goto TitleError
if "%FileTitle:~-1%" == " " goto EvaluateWord
set "LastWord=%FileTitle:~-1%%LastWord%"
set "FileTitle=%FileTitle:~0,-1%"
goto RemoveWord

:EvaluateWord
for /L %%C in (0,1,9) do (
    if not "!LastWord:%%C=!" == "%LastWord%" goto RemoveSpaces
)

rem Append the removed word as it does not contain a digit.
rem Then we have the file title and can exit the subroutine.

set "FileTitle=%FileTitle%%LastWord%"
goto :EOF

:TitleError
set "FileTitle=Error: No file title found^!"
goto :EOF

在命令提示符窗口中执行的这个批处理文件输出:

Get from  "Hello world my name is John Doe, but you knew that video5c"
the title "Hello world my name is John Doe"

Get from  "Hello world my name is Jane Doe  video3v: but you knew that"
the title "Hello world my name is Jane Doe"

Get from  "Hello world my name is Superman: but you knew that 1f"
the title "Hello world my name is Superman"

Get from  "Hello world my name is Asterix, Gallier 43: but you knew that 1f"
the title "Hello world my name is Asterix, Gallier"

Get from  "34: but you knew that this is an invalid title"
the title "Error: No file title found!"

Get from  ", but you knew that this is also an invalid title"
the title "Error: No file title found!"

Get from  " but you knew that this is an invalid title, too"
the title "Error: No file title found!"

此批处理文件中的函数GetTitle 使用命令FORSET 大量字符串替换来确定每个标题。

如果输出符合您对这些行的期望,请使用函数 GetTitle

要了解所使用的命令及其工作原理,请打开命令提示符窗口,在其中执行以下命令,并仔细阅读每个命令显示的所有帮助页面。

  • call /?
  • echo /?
  • endlocal /?
  • for /?
  • goto /?
  • if /?
  • rem /?
  • setlocal /?

我的下一个版本使用更新的示例数据:

Hello world my name is awesome
Hello world my name is awesome, but you knew that video c5
Hello world my name is awesome  video3 v: Everybody knows I am r
Hello world my name is awesome: It got 100 likes in 10 min 1f
Hello world my name is awesome 43 video 2: Did you know that:
Hello world my name is awesome a3: It is Mr smokealot 1f,

使用首次定义的规则,批处理代码现在比以前容易得多:

@echo off
setlocal EnableExtensions EnableDelayedExpansion
set "FileTitle="
for /F "usebackq delims=" %%L in ("Test.txt") do (
    call :GetTitle "%%L"
    echo Get from  "%%L"
    echo the title "!FileTitle!"
    echo.
)
endlocal
goto :EOF

:GetTitle

rem Get string left from first comma or first colon. The entire line
rem is returned if the line does not contain any comma or colon.

for /F "tokens=1 delims=,:" %%T in ("%~1") do set "WordsList=%%T"

rem Process each word from list and check for containing any digit, or being
rem a single letter different than upper case "I", or being the word "video".
rem Those words are ignored on building the file title from the words list.
rem It is expected here that non of the words contain a non word character
rem as this could result in a syntax error on processing the words.

set "FileTitle="
for %%I in (%WordsList%) do (
    set "Skip=0"
    for /F "tokens=1 delims=0123456789" %%W in ("#%%I#") do set "Word=%%W"
    if "!Word!" NEQ "#%%I#" set "Skip=1"
    set "Word=%%I"
    if "!Word:~0,1!" EQU "%%I" (
        if "%%I" NEQ "I" set "Skip=1"
    )
    if /I "%%I" EQU "video" set "Skip=1"
    if "!Skip!" EQU "0" set "FileTitle=!FileTitle! %%I"
)

rem Was there not at least 1 valid word found?

if "%FileTitle%" == "" set "FileTitle= Error: No file title found."

rem Remove the leading space and exit subroutine GetTitle.
set "FileTitle=%FileTitle:~1%"
goto :EOF

示例输入数据的输出为:

Get from  "Hello world my name is awesome"
the title "Hello world my name is awesome"

Get from  "Hello world my name is awesome, but you knew that video c5"
the title "Hello world my name is awesome"

Get from  "Hello world my name is awesome  video3 v: Everybody knows I am r"
the title "Hello world my name is awesome"

Get from  "Hello world my name is awesome: It got 100 likes in 10 min 1f"
the title "Hello world my name is awesome"

Get from  "Hello world my name is awesome 43 video 2: Did you know that:"
the title "Hello world my name is awesome"

Get from  "Hello world my name is awesome a3: It is Mr smokealot 1f,"
the title "Hello world my name is awesome"

还有一个和Stephan非常相似的版本:

@echo off
setlocal EnableExtensions EnableDelayedExpansion
set "FileTitle="
for /F "usebackq delims=" %%L in ("Test.txt") do (
    call :GetTitle "%%L"
    echo !FileTitle!
)
endlocal
goto :EOF

:GetTitle

rem Get string left from first comma or first colon. The entire line
rem is returned if the line does not contain any comma or colon.

for /F "tokens=1 delims=,:" %%T in ("%~1") do set "WordsList=%%T"

rem Process each word from list and check for containing any digit, or being
rem a single letter different than upper case "I", or being the word "video".
rem Those words are ignored and all other remaining words on building the
rem file title from the words list. It is expected here that non of the words
rem contain a non word character as this could result in a syntax error on
rem processing the words.

set "FileTitle="
for %%I in (%WordsList%) do (
    for /F "tokens=1 delims=0123456789" %%W in ("#%%I#") do set "Word=%%W"
    if "!Word!" NEQ "#%%I#" goto CheckTitle
    set "Word=%%I"
    if "!Word:~0,1!" EQU "%%I" (
        if "%%I" NEQ "I" goto CheckTitle
    )
    if /I "%%I" EQU "video" goto CheckTitle
    set "FileTitle=!FileTitle! %%I"
)

:CheckTitle
rem Was there not at least 1 valid word found?

if "%FileTitle%" == "" set "FileTitle= Error: No file title found."

rem Remove the leading space and exit subroutine GetTitle.
set "FileTitle=%FileTitle:~1%"
goto :EOF

Stephan´s answer 中发布的示例输入数据的输出是:

Hello world my name is awesome
Hello world my name is awesome
Hello world my name is awesome
Hello world my name is awesome
Hello world my name is awesome
Hello world my name is John Doe
Hello world my name is Jane Doe
Hello world my name is Superman
Hello world my name is Asterix
Error: No file title found.
Any string is
Any word that contains

Stephan 的代码产生的输出的不同之处在于,不是I 的单个字符单词会导致退出单词处理循环并因此截断该单词的标题。

可以通过删除代码行来改变这种单字符单词的行为:

    set "Word=%%I"
    if "!Word:~0,1!" EQU "%%I" (
        if "%%I" NEQ "I" goto CheckTitle
    )

那么第三个批处理代码的输出将与Stephan 编写的批处理代码产生的输出相同,除了错误消息而不是空行。


PS:这是一个很好的例子,如果提问者没有通过发布有问题的预期输出数据来明确提供的输入数据的输出数据应该是什么。

【讨论】:

  • 这几乎就是我想要的。但是现在它会搜索这个特定的字符串“但你知道”,并且该行的那部分总是随机的。我更新了我的问题。我希望现在更清楚,并希望您能进一步帮助我,因为您几乎明白了。下班后我一定会看看那些命令。谢谢
  • This is a good example what happens ... - 这是一个更好的例子,说明分析你的问题比你的实际编程技能更重要。
  • 感谢这个脚本,这正是我想要更改 .txt 文件的第一行的内容。现在我这个周末努力尝试自己修复最后一部分。也就是说,让这个脚本循环遍历一个包含很多.txt 文件的文件夹,然后更改第一行以仅保留标题,然后以与之前相同的名称保存.txt 文件。但这对我来说太难了。我花了很多时间试图修复最后一部分,但没有成功:(。如果你能帮我解决这个问题,我会非常感激,或者可能是其他人?如果没有,我明白感谢你迄​​今为止的帮助!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-30
相关资源
最近更新 更多