【问题标题】:Linux: counting spaces and other characters in fileLinux:计算文件中的空格和其他字符
【发布时间】:2012-01-30 18:59:27
【问题描述】:

问题:

我需要为邮件机软件程序匹配一个确切的格式。它需要某种格式。我可以计算新行、回车、制表符等的数量。使用诸如

之类的工具
cat -vte

od -c

wc -l ( or wc -c )

但是,我想知道字符之间的前导和尾随空格的确切数量 和文本部分。选项卡也是如此。

问题:

您将如何分析然后使用通用 unix 精确匹配模板 工具 + perl 还是 python?首选单线。另外,你对匹配有什么建议 DOS编码文件?你会先把它翻译成 NIX,然后再分析,还是照原样离开?

更新

使用它查看单个空格 [假定文件中没有 '%' 字符]:

sed 's/ /%/g' filename.000

计划构建一个脚本来分析每一行的制表符和空格内容。

使用@shiplu 的解决方案向反猫人群致敬:

while read l;do echo $l;echo $((`echo $l |  wc -c` - `echo $l | tr -d ' ' | wc -c`));done<filename.000

仍然需要对 Windows 进行一些调整,但它正在顺利进行中。

示例文本

阅读关键:

用 \n 标记的换行符

用\r标记的回车

标有 [:space:] 的未知空格/制表符(需要考虑这些)

\r\n
\n
[:space:]Institution Anon LLC\r\n
[:space:]123 Blankety St\r\n
[:space:]Greater Abyss, AK  99999\r\n
\n
\n
[:space:]                                10/27/2011\r\n
[:space:]Requested materials are available for pickup:\r\n
[:space:]e__\r[:space:]                     D_ \r[:space:]   _O\r\n
[:space:]Bathtime for BonZo[:space:]       45454545454545[:space:]  10/27/2011\r\n
[:space:]Bathtime for BonZo[:space:]       45454545454545[:space:]  10/27/2011\r\n
\n
\n
\n
\n
\n
\n
[:space:]                             Pantz McManliss\r\n
[:space:]                             Gibberish Ave\r\n
[:space:]                             Northern Mirkwood, ME  99999\r\n
( untold variable amounts of \n chars go here )

更新 2

将 IFS 与 read 结合使用会得到与下面某人发布的 ruby​​ 类似的结果。

while IFS='' read -r line
 do 
     printf "%s\n" "$line" | sed 's/ /%/g' | grep -o '%' | wc -w
 done < filename.000

【问题讨论】:

  • 你要统计space的字符数吗??
  • 是的。我认为我走在正确的轨道上。使空格和制表符可见,唯一...然后计数。我想我在下面看到有人有同样的想法。
  • 你检查我的答案了吗?
  • 非常接近,但需要逐行分析。
  • 我觉得有一个循环来了。

标签: regex linux perl shell text


【解决方案1】:
perl -nlE'say 0+( () = /\s/g );'

与当前接受的答案不同,这不会将输入拆分为字段,从而丢弃结果。它也不需要创建一个数组来计算列表中值的数量。

使用的成语:

  • 0+( ... ) 强加了类似 scalar( ... ) 的标量上下文,但它更清晰,因为它告诉读者一个数字是预期的。
  • 标量上下文中的列表赋值返回其 RHS 返回的元素数量,因此 0+( () = /.../g ) 给出了 () = /.../g 匹配的次数。
  • -l-n 一起使用时,将导致输入被“chomped”,因此这会从计数中删除换行符。

如果您只对空格 (U+0020) 和制表符 (U+0009) 感兴趣,以下方法更快更简单:

perl -nE'say tr/ \t//;'

在这两种情况下,您都可以通过 STDIN 或通过参数命名的文件传递输入。

【讨论】:

  • 不错!效果很好。仍然想知道为什么结果会因使用的解决方案而有所不同。在这个项目的范围内,这并不重要,但仍然......一个奇怪的旁注。
  • @Bubnoff,我怀疑有些计数中包含 CR 和/或 LF。我的将包括 CR。为什么你的线路在 unix 中有 CR?首先使用dos2unix 修复您的文件。
  • 这听起来像是一个合理的解释。打印机需要 DOS(或任何它所在的位置),如果可能的话,我不想对文件进行任何手术。我不想计算 CR 或 LF。所以实际上,bash 循环可能是最准确的,因为它只捕获空格?此文件中没有我可以找到的选项卡,我认为它只是空格。
  • @Bubnoff,将\s 替换为[ \t] 即可解决问题,也可以使用tr/ \t// 解决方案,因为它们专门寻找空格和制表符,而不是一般的空格。跨度>
  • perl -nE'say tr/ \t//;'产生与 bash 循环相同的结果。
【解决方案2】:

Perl 或 Python 中的正则表达式将是这里的方法。

是的,学习“perl、schmerl、zwerl”可能需要花费一些初始时间,但是一旦您获得了使用正则表达式等非常功能强大的工具的经验,它可以为您节省大量时间路上的时间。

【讨论】:

  • 我知道正则表达式。找几个单行。一开始就应该澄清。不过感谢 XKCD。
【解决方案3】:
perl -nwE 'print; for my $s (/([\t ]+)/g) { say "Count: ", length $s }' input.txt

这将计算单独的制表符或空格组,而不是计算整行中的所有空格。例如:

    foo        bar

将打印

    foo        bar
Count: 4
Count: 8

您可能希望跳过单个空格(单词之间的空格)。 IE。不要计算Bathtime for BonZo 中的空格。如果是这样,请将 + 替换为 {2,} 或您认为合适的任何最小值。

【讨论】:

  • 摇滚乐(到处都是变音符号)。我需要做一些测试,但我认为这可能是迄今为止最好的!
  • @Bubnoff 如果我确切地知道您要做什么,我可能会提供更好的答案。但我想你可以根据自己的需要进行调整。
  • 我们正在迁移到一个新系统,该系统生成的格式与我上面的示例文本不同。我需要让新系统匹配上述格式——我正在分析预期的格式,希望能在新系统中匹配它。既然分析已接近完成,我可能不得不提出一个新问题,即最好的方法。
【解决方案4】:

计算空格:

sed 's/[^ ]//g' FILE | tr -d "\n" | wc -c

文本之前、之后和之间。您想同时计算换行符、制表符等并将它们汇总,还是作为单独的步骤?

【讨论】:

  • 这非常接近......我要去的地方[见更新]。但需要计算每行的空格或制表符。您的 tr 位是一个有趣的解决方案。
【解决方案5】:

如果你想统计pm.txtspace的个数,这个命令就可以了,

 cat pm.txt | while read l; 
 do echo $((`echo $l |  wc -c` - `echo $l | tr -d ' ' | wc -c`));
 done;

如果你想统计spaces、\r\n\t的数量,就用这个,

cat pm.txt | while read l;
do echo $((`echo $l |  wc -c` - `echo $l | tr -d ' \r\n\t' | wc -c`));
done;

read 将删除所有前导字符。如果你不想要它,有一个讨厌的方法。首先使用

拆分您的文件,以便每个文件只有 1 行
`split -l 1 -d pm.txt`. 

之后会有一堆x* 文件。现在循环遍历它。

for x in x*; do echo $((`cat $x |  wc -c` - `cat $x | tr -d ' \r\n\t' | wc -c`)); done;

通过rm x*删除那些文件;

【讨论】:

  • 我可以听到“反用猫”人群的哀嚎和咬牙切齿,但我认为这是在正确的轨道上。但是,我需要逐行分析。
  • 太棒了...我在实验中遇到了循环,但你打败了我。就是这个。我只需要在中间部分将它从dos翻译成unix,我就完成了。谢谢大佬!
  • while 循环以某种方式去除前导空格。在包含多达 50 个空格的行中仅显示 3 个空格。
  • 如果我在不显示循环的情况下进行逐行分析。例如,grep "regex" -m 1 bkct.000 | sed 's/ /%/g' | grep -o '%' | wc -w
  • "# while IFS='' read -r line" 解决了这个问题。在这里找到stackoverflow.com/questions/1648055/…
【解决方案6】:

如果 Ruby 很重要(它确实 count :)

ruby -lne 'puts scan(/\s/).size'

现在还有一些 Perl(恕我直言,不太直观):

perl -lne 'print scalar(@{[/(\s)/g]})'

【讨论】:

  • 简洁美观。还有其他限制,我根本不了解 Ruby,但我会赞成简明地满足其中一项要求。我得去看看 Ruby。谢谢!
  • 谢谢。添加了一些 Perl.. 很抱歉错过了一些要求.. 让我再读一遍。
  • 太棒了!这也有效。不过,这是一个谜题。此页面上的所有三种解决方案( bash、ruby、perl )的结果相差一到两个。 Perl 每行计算的空间比 bash 和一些行少一个,但在其他行上更多的空间。我认为这将是一个相当手动的过程。
  • 好吧,我必须承认我不确定我是否完全理解您的要求 - 其他人可能也不会。所以,澄清一下:你只需要每行 1 个数字:空白字符的数量,忽略行尾。上述两个 ruby​​/perl 1-liners 似乎都满足了这一点。还有其他细微差别/要求/限制吗?对您的示例运行 bash 代码似乎也转储了这些行,去掉了前导空格(这是一个要求吗?)。这里的 ruby​​&perl 给了我与问题中的样本相同的结果。你觉得那里有什么不同?
  • 如果您查看最后一个 bash 示例,它会保留空间并给出类似的结果。 ruby 和 perl 也可以正常工作,但是这三个在不同的行上给出的结果略有不同。就好像所有三个翻译空间都略有不同。一切都足以完成项目......我只是想知道为什么结果略有不同。
【解决方案7】:

如果你问我,我会编写一个简单的 C 程序来一次性完成计数和格式化。但这只是我。等我玩完 perl、schmerl、zwerl 的放屁,我已经浪费了半天时间了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-22
    • 1970-01-01
    • 2016-03-11
    • 1970-01-01
    • 1970-01-01
    • 2023-03-19
    相关资源
    最近更新 更多