1

我有一个名为 Strings.h 的文件,我用它来本地化我拥有的应用程序。我想搜索我所有的类文件,找出我是否以及在哪里使用每个字符串,并输出每个字符串的类和行号。

我的想法是使用 Python,但也许那是适合这项工作的错误工具。另外,我有一个基本算法,但我担心运行时间太长。你能写这个脚本来做我想做的事,或者只是建议一个更好的算法吗?

Strings.h 看起来像这样:

#import "NonLocalizedStrings.h"

#pragma mark Coordinate Behavior Strings
#define LATITUDE_WORD NSLocalizedString(@"Latitude", @"used in coordinate behaviors")
#define LONGITUDE_WORD NSLocalizedString(@"Longitude", @"used in coordinate behaviors")
#define DEGREES_WORD NSLocalizedString(@"Degrees", @"used in coordinate behaviors")
#define MINUTES_WORD NSLocalizedString(@"Minutes", @"Used in coordiante behaviors")
#define SECONDS_WORD NSLocalizedString(@"Seconds", @"Used in DMSBehavior.m")

...

该脚本应获取以#define 开头的每一行,然后列出出现在#define 之后的单词(例如)LATITUDE_WORD

伪代码可能是:

file = strings.h
for line in file:
  extract word after #define
  search_words.push(word) 

print search_words
[LATITUDE_WORD, LONGITUDE_WORD, DEGREES_WORD, MINUTES_WORD, SECONDS WORD]

在获得单词列表后,我的伪代码类似于:

found_words = {}
for word in words:
   found_words[word] = []

for file in files:
  for line in file:
    for word in search_words:
      if line contains word:
        found_words[word].push((filename, linenumber))   

print found_words

因此,找到的单词看起来像:

 {
   LATITUDE_WORD: [
                    (foo.m, 42),
                    (bar.m, 132) 
                  ],
   LONGITUDE_WORD: [
                    (baz.m, 22),
                    (bim.m, 112) 
                  ],

 }
4

6 回答 6

3

这个 [in bash] 怎么样?

$ pattern="\\<($(grep '^#define ' Strings.h | cut -d' ' -f2 | tr '\n' '|' | sed 's/|$//'))\\>"
$ find project_dir -iname '*.m' -exec egrep -Hno "${pattern}" {} + > matches

输出:

project_dir/bar.m:132:LATITUDE_WORD
project_dir/baz.m:22:LONGITUDE_WORD
project_dir/bim.m:112:LONGITUDE_WORD
project_dir/foo.m:42:LATITUDE_WORD

编辑:我已经更改了上面的代码以将其输出重定向到文件matches,因此我们可以使用它来显示从未找到的单词:

for word in $(grep '^#define ' Strings.h | cut -d' ' -f2)
do
    if ! cut -d':' -f3 matches | grep -q "${word}"
    then
        echo "${word}"
    fi
done
于 2012-10-31T02:39:18.650 回答
2

所以,看起来你的想法是对的。以下是您所拥有的一些优点和缺点。

优点:

  • 如果您使用 Python,您的伪代码几乎会逐行直接转换为您的脚本。
  • 你可以学习更多关于 Python 的知识(对于这样的事情有很好的技能)。

缺点:

  • Python 的运行速度将比已发布的其他一些基于 bash 的解决方案慢一些(如果您有很多文件要搜索,这将是一个问题)。
  • 您的 Python 脚本将比这些其他解决方案长一点,但您的输出也可以更灵活一点。

答: 因为我熟悉 Python,而这正是您最初要求的,所以您可以使用更多代码:

#!/usr/bin/env python

# List the files you want to search here
search_files = []
word_file = open('<FILE_PATH_HERE>', 'r')

# Allows for sorted output later.
words = []

#Contains all found instances.
inst_dict = {}

for line in word_file:
    if line[0:7] == "#define":
        w = line[7:].split()[0]
        words.append(w)
        inst_dict[w] = []

for file_name in search_files:
    file_obj = open(file_name, 'r')
    line_num = 0
    for line in file_obj:
        for w in words:
            if w in line:
                inst_dict[w].append((file_name,line_num))
        line_num += 1

# Do whatever you want with 'words' and 'inst_dict'
words.sort()
for w in words:
    string = w + ":\n"
    for inst in inst_dict[w]:
        string += "\tFile: " + inst[0] + "\n"
        string += "\tLine: " + inst[1] + "\n"
    print string

我没有测试代码的搜索部分,所以使用“原样”需要您自担风险。祝你好运,随时提出问题或根据需要扩充代码。您的请求非常简单并且有很多解决方案,所以我希望您了解它是如何工作的。

于 2012-10-31T03:38:14.397 回答
1

此解决方案使用awkand globstar(后者需要 Bash 4)。我认为可以进一步改进,但认为这是一种草稿。

shopt -s globstar

awk 'NR==FNR { if ($0 ~ /^#define/) found[$2]=""; next; } 
     {
       for (word in found){
         if ($0 ~ word) 
           found[word]=found[word] "\t" FILENAME ":" FNR "\n";
       } 
     }
     END { for (word in found) print word ":\n" found[word]}
    ' Strings.h **/*.m  

使用您发布的 Strings.h 片段,这是我得到的输出类型(我编写了一些测试文件)

LATITUDE_WORD:
    lala1.m, 2
    lala3.m, 1

DEGREES_WORD:
    lala2.m, 5

SECONDS_WORD:

MINUTES_WORD:
    lala3.m, 3

LONGITUDE_WORD:
    lala3.m, 2

p/s:globstar由于我现在使用的 bash 是 v3(pfff!) ,因此尚未对此进行测试

于 2012-10-31T08:03:44.533 回答
0

你应该试试 :

grep -oP '^#define\s+\K\S+' strings.h

如果您grep缺少该-P选项:

perl -lne 'print $& if /^#define\s+\K\S+/' strings.h
于 2012-10-31T02:24:33.167 回答
0

这是一个 Python 程序。它可能可以减少并变得更简单,但它确实有效。

import re
l=filecontent.split('\n')
for item in l:
  if item.startswith("#define"):
    print re.findall("#define .+? ", item)[0].split(' ')[1]
于 2012-10-31T02:37:54.063 回答
0
#!/bin/bash
# Assuming $files constains a list of your files
word_list=( $(grep '^#define' "${files[@]}" | awk '{ print $2 }') )
于 2012-10-31T02:53:53.593 回答