【问题标题】:Select lines from two files containing matching strings从包含匹配字符串的两个文件中选择行
【发布时间】:2015-10-03 22:19:40
【问题描述】:

假设我有两个文件 A 和 B。A 的内容:

foo1 foo2
bar1 bar3

B的内容:

bar2 bar3
foo3 foo4

如何从 A 中选择第二行,从 B 中选择第一行?没有搜索字符串。我需要选择包含所有可能的公共字符串的行。

请注意,我不是从两个不同的文件中寻找匹配的行。所需的行不相同,但包含一个公共字符串。

任何帮助将不胜感激。谢谢!

【问题讨论】:

  • 您是在构建一些应用程序还是什么?如果属实,那么使用哪种语言?
  • 不,我有两个列表 - 音频文件的位置及其副本(不共享类似的目录结构)。但是音频文件总是比成绩单多,所以我只想选择那些有相应成绩单的文件。
  • 你的问题是矛盾的。您的一段段落指出“[t]这里没有搜索字符串”。然后你的倒数第二段说所需的行包含“查询字符串”。您对“搜索字符串”的定义是什么,它与“查询字符串”有何不同?
  • 很抱歉给您带来了困惑。将“查询字符串”编辑为“通用字符串”。解决方案必须检查所有可能的公共字符串
  • 我也需要同样的。有人给点办法

标签: pattern-matching match text-processing


【解决方案1】:

TXR Lisp中的解决方案:

$ txr common-word-lines.tl file1 file2 酒吧 1 酒吧 3 酒吧 2 酒吧 3

common-word-lines.tl中的代码:

(defun hash-file-words (name)
  (with-stream (s (record-adapter #/\s+/ (open-file name "r")))
    (hash-list (get-lines s) :equal-based)))

(defun lines-containing-words-in-both-hashes (name hash1 hash2)
  (let ((s (open-file name "r")))
    (mappend*
      (op if [some (tok-str @1 #/\S+/) (andf hash1 hash2)]
        (list @1))
      (get-lines s))))

(tree-case *args*
  ((file1 file2 extra . junk) (throwf 'error "too many arguments"));
  ((file1 file2)
   (let ((hash1 (hash-file-words file1))
         (hash2 (hash-file-words file2)))
     (put-lines (lines-containing-words-in-both-hashes file1 hash1 hash2))
     (put-lines (lines-containing-words-in-both-hashes file2 hash1 hash2))))
  (else (throwf 'error "insufficient arguments")))

这会两次遍历文件。在第一遍中,我们构建了两个文件中所有以空格分隔的单词的哈希。在第二遍中,我们打印每个文件中的每一行,其中至少包含一个出现在两个哈希中的单词。

使用了惰性列表处理,因此虽然看起来我们正在一次读取整个文件,但实际上并非如此。 get-lines 返回一个惰性列表。在hash-file-words 中,文件实际上正在被读取,因为hash-list 函数正在沿着传递给它的惰性列表前进。在lines-containing-words-in-both-hashes 中,使用了mappend*,它懒惰地过滤列表并附加片段。

(andf hash1 hash2) 是什么?首先,andf 是一个组合子。它接受多个都是函数的参数,并返回一个函数,该函数是这些函数的短路与组合。 (andf a b c) 产生一个函数,该函数将其参数传递给函数a。如果返回nil (false),它将停止并返回nil。否则,它将其参数传递给b,并应用相同的逻辑。如果它一直到达c,则返回c 返回的任何值。其次,虽然hash1hash2 是哈希表,但是它们可以在TXR Lisp 中用作函数。哈希表表现为一个单参数函数,它在哈希表中查找其参数,并返回相应的值,否则nil。因此,(andf hash1 hash2) 只需使用 AND 组合符来构建一个函数,如果其参数存在于两个哈希表中(与非nil 值相关联),则该函数返回 true。

因此,[some (tok-str @1 #/\S+/) (andf hash1 hash2)] 的意思是“将行标记为单词,并报告其中一些是否在两个哈希中”。 @1(op ...) 宏生成的匿名函数的隐式参数。为(get-lines) 生成的列表中的每个元素调用该函数;即文件的每一行。所以@1依次表示每一行。

更通用的版本:更短,并处理两个或多个参数:

(defun hash-file-words (name)
  (with-stream (s (record-adapter #/\s+/ (open-file name "r")))
    (hash-list (get-lines s) :equal-based)))

(defun lines-containing-words-in-all-hashes (name hashes)
  (let ((s (open-file name "r")))
    (mappend*
      (op if [some (tok-str @1 #/\S+/) (andf . hashes)]
        (list @1))
      (get-lines s))))

(unless *args*
  (put-line `specify one or more files`)
  (exit 1))

(let ((word-hashes [mapcar hash-file-words *args*]))
  (each ((file *args*))
    (put-lines (lines-containing-words-in-all-hashes file word-hashes))))

【讨论】:

    猜你喜欢
    • 2021-12-09
    • 2013-01-09
    • 1970-01-01
    • 2020-08-18
    • 2014-11-17
    • 1970-01-01
    • 1970-01-01
    • 2021-10-18
    • 2019-04-24
    相关资源
    最近更新 更多