2010-06-29 38 views
7

Tôi cố gắng để di chuyển một số mã từ một lược đồ tên cũ sang cái mới lược đồ đặt tên cũ là:Sed để loại bỏ dấu gạch dưới và thúc đẩy nhân vật

int some_var_name; 

một mới là

int someVarName_: 

Vì vậy, những gì tôi sẽ ilke là một số hình thức của sed/regexy tốt đẹp để giảm bớt quá trình. Vì vậy, về cơ bản những gì cần phải xảy ra là:
tìm từ chữ thường có chứa _ thay thế dấu gạch dưới không có gì và quảng bá char ở bên phải của _ thành chữ hoa. Sau khi điều này thêm một _ vào cuối trận đấu.

Có thể thực hiện điều này với Sed và/hoặc Awk và regex không? Nếu không, tai sao không?

Bất kỳ tập lệnh mẫu nào đều sẽ được đánh giá cao.

cảm ơn rất nhiều vì đã hỗ trợ.

EDIT:
Đối với một chút rõ ràng, đổi tên là cho một số tệp được viết sai quy ước đặt tên và cần phải được đưa vào phù hợp với phần còn lại của codebase. Nó không phải là dự kiến ​​rằng điều này làm một thay thế hoàn hảo mà lá tất cả mọi thứ trong một nhà nước compilable. Thay vì kịch bản sẽ được chạy và sau đó nhìn qua bằng tay cho bất kỳ sự bất thường. Các kịch bản thay thế sẽ được hoàn toàn để giảm bớt gánh nặng của việc phải sửa chữa tất cả mọi thứ bằng tay, mà tôi chắc chắn rằng bạn sẽ đồng ý là khá tẻ nhạt.

+0

có dấu gạch dưới nào trong mã bên cạnh các tên biến không? – drfrogsplat

+0

umm có trong các hằng số, ví dụ:SOME_CONSTANT, những điều này sẽ không phải chịu bất kỳ thay đổi nào. – radman

Trả lời

4

sed -re 's,[a-z]+(_[a-z]+)+,&_,g' -e 's,_([a-z]),\u\1,g'

Giải thích :

Đây là lệnh sed có 2 biểu thức (mỗi dấu ngoặc kép sau -e.) s,,,g là sự thay thế toàn cầu. Bạn thường thấy nó với dấu gạch chéo thay vì dấu phẩy, nhưng tôi nghĩ rằng điều này dễ đọc hơn khi bạn sử dụng dấu gạch chéo ngược trong các mẫu (và không có dấu phẩy). Dấu g (cho "toàn cầu") có nghĩa là áp dụng thay thế này cho tất cả các kết quả phù hợp trên mỗi dòng, chứ không phải chỉ là kết quả đầu tiên.

Biểu thức đầu tiên sẽ thêm dấu gạch dưới vào mỗi mã thông báo được tạo thành từ chữ thường ([a-z]+) theo sau là một số chữ thường không phân tách bằng dấu gạch dưới ((_[a-z]+)+). Chúng tôi thay thế điều này bằng &_, trong đó & có nghĩa là "mọi thứ phù hợp" và _ chỉ là dấu gạch dưới chữ. Vì vậy, tổng cộng, biểu thức này đang nói thêm dấu gạch dưới vào cuối mỗi underscore_separated_lowercase_token.

Biểu thức thứ hai khớp với mẫu _([a-z])), trong đó mọi thứ giữa () là nhóm chụp. Điều này có nghĩa là chúng tôi có thể tham khảo lại sau này là \1 (vì đây là nhóm chụp đầu tiên. Nếu có nhiều hơn, họ sẽ là \2, \3, v.v.). Vì vậy, chúng tôi đang nói để phù hợp với một chữ cái thường sau dấu gạch dưới, và nhớ lá thư.

Chúng tôi thay thế bằng \u\1, là chữ cái mà chúng tôi vừa nhớ, nhưng được viết hoa theo số \u.

Mã này không làm bất kỳ điều gì thông minh để tránh bị cắt #include dòng hoặc loại tương tự; nó sẽ thay thế mọi thể hiện của một chữ thường sau dấu gạch dưới với chữ hoa tương đương của nó.

+0

BTW, sed -i $ filename là cách bạn sẽ gọi sed để chỉnh sửa $ filename tại chỗ. Vì vậy, bạn có thể làm, ví dụ: "sed -i -r -e ... * .c" – Vineet

+0

Cảm ơn bạn đã trả lời Vineet, trước tiên bạn đã có giải pháp khả thi và hoạt động chính xác theo yêu cầu. Cũng đạo cụ cho lời giải thích rõ ràng về chức năng của lệnh Sed. – radman

3

Cân nhắc sử dụng sed để tìm kiếm và thay thế tất cả văn bản như thế này. Nếu không có trình thông báo C++ để nhận dạng số nhận dạng (và cụ thể là số nhận dạng của bạn và không phải là số nhận dạng trong thư viện chuẩn, ví dụ), bạn là bị rung. push_back được đổi tên thành pushBack_. bản đồ :: chèn vào bản đồ :: insert_. ánh xạ tới map_. basic_string đến basicString_. printf để printf_ (nếu bạn sử dụng thư viện C), vv Bạn sẽ ở trong một thế giới bị tổn thương nếu bạn làm điều đó bừa bãi.

Tôi không biết bất kỳ công cụ hiện có nào để tự động đổi tên some_var_name thành someVarName_ mà không có sự cố được mô tả ở trên. Mọi người đã bỏ phiếu bài đăng này có lẽ vì họ không hiểu ý tôi ở đây. Tôi không nói sed không thể làm điều đó, Tôi chỉ nói rằng nó sẽ không cung cấp cho bạn những gì bạn muốn để chỉ sử dụng nó như là. Trình phân tích cú pháp cần thông tin theo ngữ cảnh để làm điều này đúng, nếu không nó sẽ thay thế nhiều thứ hơn nó không nên. Bạn có thể viết một trình phân tích cú pháp có thể thực hiện điều này (ví dụ: sử dụng sed) nếu nó có thể nhận dạng mã thông báo nào (cụ thể là mã định danh của bạn), nhưng tôi nghi ngờ có một công cụ cụ thể cho những gì bạn muốn làm làm nó ra khỏi con dơi mà không có một số mỡ khuỷu tay bằng tay (mặc dù tôi có thể sai). Làm một tìm kiếm đơn giản và thay thế trên tất cả các văn bản theo cách này sẽ là vấn đề.

Tuy nhiên, Visual AssistX (có thể tùy ý thay thế các cá thể trong tài liệu) hoặc bất kỳ công cụ tái cấu trúc nào khác có khả năng đổi tên thông minh định danh cho mọi trường hợp mà chúng xuất hiện ít nhất là giảm bớt gánh nặng của mã tái cấu trúc theo cách này khá đáng kể. Nếu bạn có một biểu tượng tên là some_var_name và nó được tham chiếu trong hàng nghìn địa điểm khác nhau trong hệ thống của bạn, với VAssistX bạn có thể sử dụng một hàm đổi tên để đổi tên tất cả các tham chiếu một cách thông minh (đây không phải là tìm kiếm văn bản và thay thế). Check out the refactoring features of Visual Assist X.Có thể mất 15 phút đến nửa giờ để refactor một trăm biến theo cách này với VAX (nhanh hơn nếu bạn sử dụng phím nóng), nhưng nó chắc chắn nhịp đập bằng cách sử dụng tìm kiếm văn bản và thay thế bằng sed như được mô tả trong câu trả lời khác và có tất cả các loại mã thay thế mà không nên thay thế.

[chủ quan] BTW: dấu gạch dưới vẫn không thuộc về trường hợp lạc đà nếu bạn hỏi tôi. Quy ước đặt tên lowerCamelCase nên sử dụng lowerCamelCase. Có rất nhiều giấy tờ thú vị về điều này, nhưng ít nhất là quy ước của bạn là nhất quán. Nếu đó là phù hợp, thì đó là một điểm cộng lớn như trái ngược với một cái gì đó giống như fooBar_Baz mà một số lập trình viên ngốc nghếch viết ai nghĩ nó bằng cách nào đó làm cho mọi thứ dễ dàng hơn để làm cho trường hợp ngoại lệ đặc biệt để các quy tắc. [/ Chủ quan]

+0

để làm rõ quy ước đặt tên được hiển thị cho các biến thành viên, dấu gạch dưới ở cuối là xác định chúng như vậy. Tôi thích điều này để m_varName hoặc _varName. Ngoài ra tôi đã có khả năng tái cấu trúc bằng cách sử dụng QT Creator nhưng tôi vẫn không ưa thích tay thay đổi 100 hoặc hơn biến. – radman

+0

Thật không may, đây là cách đáng tin cậy duy nhất tôi biết về các công cụ hiện có để thực hiện việc này. Bạn không thể tìm kiếm và thay thế các tệp nguồn một cách bừa bãi với sed hoặc bất kỳ trình phân tích cú pháp regex chung nào khác mà không cần thay thế nhiều thứ mà bạn không muốn thay thế, thường tốn nhiều thời gian hơn sử dụng công cụ tái cấu trúc như VAX chọn lọc đổi tên mọi thứ. – stinky472

+0

+1 Tôi đồng ý với bạn rằng _sed_ là nguy hiểm. Và đó là mỡ khuỷu tay là cần thiết. –

3

Một vài năm trước, tôi đã chuyển thành công một mã 300.000 LOC cơ sở 23 tuổi di sản thành camelCase. Chỉ mất hai ngày. Nhưng có một vài ảnh hưởng kéo dài mất vài tháng để phân loại. Và nó là rất cách tốt để làm phiền các lập trình viên đồng nghiệp của bạn.

Tôi tin rằng cách tiếp cận đơn giản, câm, giống như sed có lợi thế.IDE dựa trên các công cụ, và như thế, không thể, như xa như tôi biết:

  • thay đổi mã không biên soạn thông qua mã thay đổi
  • # ifdef trên comment

Và mã di sản có được duy trì trên một số nền tảng trình biên dịch/hệ điều hành khác nhau (= rất nhiều #ifdefs).

Chính bất lợi bất lợi của một cách tiếp cận câm, giống như sed là các chuỗi (chẳng hạn như từ khóa) vô tình có thể bị thay đổi. Và tôi chỉ làm điều này cho C; C++ có thể là một loại cá khác.

Có khoảng năm giai đoạn:

1) Generate a list of tokens that you wish to change, and manually edit. 
2) For each token in that list, determine the new token. 
3) Apply these changes to your code base. 
4) Compile. 
5) Double-check via a manual diff, and do a final clean-up. 

Đối với bước 1, để tạo ra một danh sách các thẻ mà bạn muốn thay đổi, lệnh:

cat *.[ch] | sed 's/\([_A-Za-z0-9][_A-Za-z0-9]*\)/\nzzz \1\n/g' | grep -w zzz | sed 's/^zzz //' | grep '_[a-z]' | sort -u > list1 

sẽ sản xuất trong list1:

st_atime 
time_t 
... 

Trong mẫu này, bạn thực sự không muốn thay đổi hai mã thông báo này, vì vậy hãy chỉnh sửa danh sách theo cách thủ công để xóa chúng . Nhưng bạn có lẽ sẽ bỏ lỡ một số, vì vậy, vì lợi ích của ví dụ này, giả sử bạn giữ chúng.

Bước tiếp theo, 2, là tạo tập lệnh để thực hiện các thay đổi. Ví dụ, lệnh:

cat list1 | sed 's/\(.*\)/glob_sub "\\<\1\\>" xxxx_\1/;s/\(xxxx_.*\)_a/\1A/g;s/\(xxxx_.*\)_b/\1B/g;s/\(xxxx_.*\)_a/\1C/g;s/\(xxxx_.*\)_t/\1T/g' | sed 's/zzz //' > list2 

sẽ thay đổi _a, _b, _C, và _T đến A, B, C và T, để sản xuất:

glob_sub "\<st_atime\>" xxxx_stAtime 
glob_sub "\<time_t\>" xxxx_timeT 

Bạn chỉ cần mở rộng nó để bìa d, e, f, ..., x, y, z,

Tôi giả sử bạn đã viết một cái gì đó như 'glob_sub' cho môi trường phát triển của bạn. (Nếu không, bỏ ngay bây giờ.) Phiên bản của tôi (csh, Cygwin) trông giống như:

#!/bin/csh 
foreach file (`grep -l "$1" */*.[ch] *.[ch]`) 
    /bin/mv -f $file $file.bak 
    /bin/sed "s/$1/$2/g" $file.bak > $file 
end 

(Một số của sed của tôi không hỗ trợ tùy chọn --Trong chỗ, vì vậy tôi phải sử dụng một mv .)

Bước thứ ba là áp dụng tập lệnh này trong danh sách2 vào cơ sở mã của bạn. Ví dụ, trong csh sử dụng source list2.

Bước thứ tư là biên dịch. Trình biên dịch sẽ (hy vọng!) Đối tượng xxxx_timeT. Thật vậy, nó có thể sẽ chỉ phản đối timeT nhưng thêm xxx_ thêm bảo hiểm. Vì vậy, đối với time_t bạn đã phạm sai lầm. Hoàn tác nó với ví dụ:

glob_sub "\<xxxx_timeT\>" time_t 

Bước thứ năm và cuối cùng là để làm một kiểm tra thủ công thay đổi của bạn sử dụng tiện ích khác mà bạn yêu thích, và sau đó dọn dẹp bằng cách loại bỏ tất cả các mong muốn xxx_ tiền tố. Tham lam cho "xxx_ cũng sẽ giúp kiểm tra mã thông báo bằng chuỗi. (Thật vậy, việc thêm hậu tố _xxx có thể là một ý tưởng hay.)

+0

+1 để hiển thị cách sử dụng sed để thực sự xây dựng giải pháp thích hợp. Lưu ý rằng việc lọc danh sách này theo cách thủ công để chọn không tham gia tất cả số nhận dạng bạn không muốn thay thế có thể tốn nhiều thời gian hơn việc chọn tham gia tất cả số nhận dạng bạn muốn thay thế. – stinky472

+0

@ stinky472: Cảm ơn bạn đã bình luận. Tôi đã hồi tưởng từ năm năm trước. Và tôi nhận ra tôi đã bỏ qua một điểm mấu chốt. Các vấn đề với những thứ như time_t là _negligible_ - đây là C, chứ không phải BOOST. Thay vào đó, đó là các tệp tiêu đề của bên thứ ba được sử dụng để nhắn tin và được thay đổi sau vài tháng. Vì vậy, chúng tôi không thể chạm vào chúng. Nhưng chúng tôi đã chạy tập lệnh đầu tiên trên các tệp tiêu đề này để xác định mã thông báo cần _not_ được thay đổi và sau đó sử dụng 'uniq -u' để có được sự khác biệt được đặt:' cat a b b | sắp xếp | uniq -u' cho 'a - b'. Bạn cũng có thể áp dụng điều này vào/usr/include/để thoát khỏi time_t. –

+0

** Chỉnh sửa: ** Nếu bạn có một gnu sed gần đây, trong bước thứ hai thay vì có 26 chuyển đổi _a thành A, _b thành B, v.v, bạn có thể sử dụng 's/\\ (xxxx _. * \\) _ \\ ([az] \\)/\ 1 \ u \ 2/g' để thay đổi _x thành X, trong đó x là từ a đến z. –

Các vấn đề liên quan